Kotlin学习教程(一)
2017-12-01 10:20
253 查看
在
5月18日谷歌在
I/O开发者大会上宣布,将
Kotlin语言作为安卓开发的一级编程语言。并且会在
Android Studio 3.0版本全面支持
Kotlin。
Kotlin是一个基于
JVM的新的编程语言,由
JetBrains开发。
JetBrains作为目前广受欢迎的
Java IDE IntelliJ的提供商,在
Apache许可下已经开源其
Kotlin编程语言。
Kotlin可以编译成
Java字节码,也可以编译成
JavaScript,方便在没有
JVM的设备上运行。
Kotlin已正式成为
Android官方开发语言。
Kotlin官网
很多开发者都说
android的
swift版本,一定会搞不起来没人用,所以不用浪费时间去学习。在这里想引用马云的一句话:
拥抱变化
Android Studio时也是一片骂声,吐槽各种不好用,各种慢。但是现在
Android Studio基本都已经普及了。我相信
Kotlin也不会例外。所以我们不仅要学,还要要认真的学。
Kotlin
的特性
它更加易表现:这是它最重要的优点之一。你可以编写少得多的代码。Kotlin是一种兼容
Java的语言
Kotlin比
Java更安全,能够静态检测常见的陷阱。如:引用空指针
Kotlin比
Java更简洁,通过支持
variable type inference,higher-order functions (closures),extension functions,mixins and first-class delegation等实现
Kotlin可与
Java语言无缝通信。这意味着我们可以在
Kotlin代码中使用任何已有的
Java库;同样的
Kotlin代码还可以为
Java代码所用
Kotlin在代码中很少需要在代码中指定类型,因为编译器可以在绝大多数情况下推断出变量或是函数返回值的类型。这样就能获得两个好处:简洁与安全
上面说简洁简洁,到底简洁在哪里?这里先用一个例子开始,在
Java开发过程中经常会写一些
Bean类:
public class Artist { private long id; private String name; private String url; private String mbid; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getMbid() { return mbid; } public void setMbid(String mbid) { this.mbid = mbid; } @Override public String toString() { return "Artist{" + "id=" + id + ", name='" + name + '\'' + ", url='" + url + '\'' + ", mbid='" + mbid + '\'' + '}'; } }
使用
Kotlin:
data class Artist( var id: Long, var name: String, var url: String, var mbid: String)
这个数据类,它会自动生成所有属性和它们的访问器,以及一些有用的方法,比如
toString()方法。
创建Kotlin
项目
Android Studio 3.0版本会全面支持
Kotlin,目前早就有预览版了Android Studio Preview(个人感觉很好用,比2.3.3版本强多了)。直接通过
New Project创建就可以,与创建普通
Java项目唯一不同的是要勾选
Include Kotlin support的选项。
创建完成后我们看一下
MainActivity的代码:
// 定义包 package com.charon.kotlinstudydemo // 导入 import android.support.v7.app.AppCompatActivity import android.os.Bundle // 定义类,继承AppCompatActivity class MainActivity : AppCompatActivity() { // 重写方法用overide,函数名用fun声明 参数是a: 类型的形式 ?是啥?它是指明该对象可能为null override fun onCreate(savedInstanceState: Bundle?) { // super super.onCreate(savedInstanceState) // 调用方法 setContentView(R.layout.activity_main) } }
我们就从
MainActivity的代码开始介绍一些基本的语法。
变量
变量可以很简单地定义成可变var和不可变
val的变量。
val与
Java中使用的
final很相似。一个不可变对象意味着它在实例化之后就不能再去改变它的状态了。如果你需要一个这个对象修改之后的版本,那就会再创建一个新的对象。
声明:
val i: Int = 7 var j: String = "haha"
字面上可以写明具体的类型。这个不是必须的,但是一个通用的
Kotlin实践时省略变量的类型我们可以让编译器自己去推断出具体的类型:
val i = 12 // An Int val iHex = 0x0f // 一个十六进制的Int类型 val l = 3L // A Long val d = 3.5 // A Double val f = 3.5F // A Float
在
Kotlin中,一切都是对象。没有像
Java中那样的原始基本类型。
当然,像
Integer,
Float或者
Boolean等类型仍然存在,但是它们全部都会作为对象存在的。基本类型的名字和它们工作方式都是与
Java非常相似的,但是有一些不同之处你可能需要考虑到:
数字类型中不会自动转型。举个例子,你不能给
Double变量分配一个
Int。必须要做一个明确的类型转换,可以使用众多的函数之一:
val i:Int=7 val d: Double = i.toDouble() val c: Int c = 3
字符(Char)不能直接作为一个数字来处理。在需要时我们需要把他们转换为一个数字:
val c: Char='c' val i: Int = c.toInt()
位运算也有一点不同。在
Android中,我们经常在
flags中使用
或:
// Java int bitwiseOr = FLAG1 | FLAG2; int bitwiseAnd = FLAG1 & FLAG2;
// Kotlin val bitwiseOr = FLAG1 or FLAG2 val bitwiseAnd = FLAG1 and FLAG2
一个
String可以像数组那样访问,并且被迭代:
val s = "Example" val c = s[2] // 这是一个字符'a' // 迭代String val s = "Example" for(c in s){ print(c) }
编译期常量
已知值的属性可以使用
const修饰符标记为编译期常量(类似
java中的
public static final)。这些属性需要满足以下要求:
位于顶层或者是
object的一个成员
用
String或原生类型值初始化
没有自定义
getter
这些属性可以用在注解中:
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated" @Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { …… }
后端变量
Backing Fields.
在
kotlin的
getter和
setter是不允许本身的局部变量的,因为属性的调用也是对
get的调用,因此会产生递归,造成内存溢出。
例如:
var count = 1 var size: Int = 2 set(value) { Log.e("text", "count : ${count++}") size = if (value > 10) 15 else 0 }
这个例子中就会内存溢出。
kotlin为此提供了一种我们要说的后端变量,也就是
field。编译器会检查函数体,如果使用到了它,就会生成一个后端变量,否则就不会生成。
我们在使用的时候,用
field代替属性本身进行操作。
延迟初始化
我们说过,在类内声明的属性必须初始化,如果设置非
null的属性,应该将此属性在构造器内进行初始化。 假如想在类内声明一个
null属性,在需要时再进行初始化(最典型的就是懒汉式单例模式),与
Kotlin的规则是相背的,此时我们可以声明一个属性并延迟其初始化,此属性用
lateinit修饰符修饰。
// 延迟初始化声明 lateinit var late : String fun initLate(){ late = "I am late" } // 先调用方法,再调用属性 var pf = PropertiesFields() pf.initLate() Log.d("text", pf.late) // 输出 I am late
需要注意的是,我们在使用的时候,一定要确保属性是被初始化过的,通常先调用初始化方法,否则会有异常。
类的定义:使用class
关键字
类可以包含:构造函数和初始化块
函数
属性
嵌套类和内部类
对象声明
class MainActivity{ }
如果有参数的话你只需要在类名后面写上它的参数,如果这个类没有任何内容可以省略大括号:
class Person(name: String, surname: String)
创建类的实例
val person = Person("charon")
上面的类有一个默认的构造函数。
构造函数
在Kotlin中的一个类可以有一个主构造函数和一个或多个次构造函数。
主构造函数
主构造函数是类头的一部分:它跟在类名(和可选的类型参数)后:
class Person constructor(name: String, surname: String) { }
如果主构造函数没有任何注解或者可见性修饰符,可以省略
constructor关键字:
class Person(name: String, surname: String) { }
主构造函数不能包含任何的代码。初始化的代码可以放到以
init关键字作为前缀的初始化块中:
class Person constructor(name: String, surname: String) { init { print("name is $name and surname is $surname") } }
如果构造函数有注解或可见性修饰符,那么
constructor关键字是必需的,并且这些修饰符在它前面:
class Person private @Inject constructor(name: String, surname: String) { init { print("name is $name and surname is $surname") } }
次构造函数
类也可以声明前缀有
constructor的次构造函数:
class Person{ constructor(name: String) { print("name is $name") } }
如果类有一个主构造函数,每个次构造函数都需要委托给主构造函数(不然会报错), 可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用
this关键字即可:
class Person constructor(name: String) { constructor(name: String, surName: String) : this(name) { Log.d("@@@", "name is : $name surName is : $surName") } }
使用该对象:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) Person("charon", "chui") } }
就会在
logcat上打印:
09-20 16:51:19.738 6010-6010/com.charon.kotlinstudydemo D/@@@: name is : charon surName is : chui
如果一个非抽象类没有声明任何(主或次)构造函数,它会有一个生成的不带参数的主构造函数。构造函数的可见性是
public。如果你不希望你的类有一个公有构造函数,你需要声明一个带有非默认可见性的空的主构造函数:
class Person private constructor(name: String) { }
接口:使用interface
关键字
interface FlyingAnimal { fun fly() }
函数:通过fun
关键字定义
fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) }
如果你没有指定它的返回值,它就会返回
Unit与
Java中的
void类似,但是
Unit是一个真正的对象。
Unit可以省略,
你当然也可以指定任何其它的返回类型:
fun maxOf(a: Int, b: Int): Int { if (a > b) { return a } else { return b } }
然而如果返回的结果可以使用一个表达式计算出来,你可以不使用括号而是使用等号:
fun add(x: Int,y: Int) : Int = x + y
我们可以给参数指定一个默认值使得它们变得可选,这是非常有帮助的。这里有一个例子,在
Activity中创建了一个函数用来
Toast一段信息:
fun toast(message: String, length: Int = Toast.LENGTH_SHORT) { Toast.makeText(this, message, length).show() }
上面代码中第二个参数
length指定了一个默认值。这意味着你调用的时候可以传入第二个值或者不传,这样可以避免你需要的重载函数:
toast("Hello") toast("Hello", Toast.LENGTH_LONG)
自定义
get set方法:
Kotlin会默认创建
set get方法,我们也可以自定义
get set方法:
kotlin预留了一个在
set和
get中访问的变量
field关键字:
class Person constructor() { var name: String = "" get() = field set(value) { field = "$value" } var age: Int = 0 get() = field set(value) { field = value } }
按照惯例
set参数的名称是
value,但是如果你喜欢你可以选择一个不同的名称。
可变长参数函数:使用
vararg关键字
fun vars(vararg v:Int){ for(vt in v){ print(vt) } } // 测试 fun main(args: Array<String>) { vars(1,2,3,4,5) // 输出12345 }
注释
和Java差不多
// 这是一个行注释 /* 这是一个多行的 块注释。 */
相关文章推荐
- Kotlin 官方学习教程之属性和字段
- Kotlin教程学习-操作符,操作符重载
- Kotlin学习教程(二)
- Kotlin教程学习-伴生对象,getter,setter,内部,局部,匿名类,可变参数
- Kotlin教程学习-HelloWorld
- Kotlin教程学习-Why Kotlin?
- Kotlin学习教程
- Kotlin学习教程(一)
- Kotlin学习教程(四)
- Kotlin教程学习-控制流
- Kotlin教程学习-函数定义,变量声明
- Kotlin学习教程(一)
- Kotlin学习教程(四)
- Kotlin 官方学习教程之接口
- kotlin 官方学习教程之基础语法详解
- kotlin 官方学习教程之编码风格
- Kotlin学习教程(一)
- Kotlin学习教程(四)
- Kotlin 官方学习教程之返回和跳转
- Kotlin教程学习-控制流