1.1 函数:
代码语言:javascript复制fun sum(a: Int, b: Int): Int {
return a b
}
// 对于只有一行的函数,kotlin可以这么简写,爽不?
fun sum(a:Int, b:Int): Int = a b
可以看到函数的声明是通过fun关键字的,函数的参数类型和参数名的位置跟Java是相反的,中间使用 : 分隔,函数的返回类型是放在最后的,当然也是使用 : 进行分割的,如果没有返回值的时候可以省略或者使用Unit,相当于Java的void。
1.2 变量:
代码语言:javascript复制var age:Int = 18
val name:String = "Kotlin"
val person = Person()
使用var来声明可读可写变量,使用val来声明只读变量(引用不可变)。 val可以理解为Java中的属性声明加上了final关键字(将kotlin的字节码反编译成Java一看就知道了),其实kotlin是更倾向于推荐使用val来声明变量,这是一种防御性的编码思维模式,目的是减少程序出错或者变的更加安全。 可以看到实例化Person对象时,并没有声明变量类型,这就是Kotlin的“类型推断”,会自动推断出是Person类型的变量,而且是不需要Java中的new关键字的。
1.3 继承和实现接口
代码语言:javascript复制class MyActivity: Activity(), View.OnClickListener {
// 省略
}
一看就懂,不用多说吧。注意加上(),如果你的kotlin类能够被继承,需要使用open关键字,因为默认是final的:
代码语言:javascript复制open class Person {
constructor(age: Int)
var age: Int = 0
}
// 当你的构造函数调用父类的构造函数时,要去掉Person后面的()
class Man: Person {
// 使用super调用父类的构造器
constructor(age: Int): super(age)
}
1.4 空安全设计
代码语言:javascript复制// 不可空类型
val person: Person
// 可空类型
val person2: Person?
那么对于可空类型的变量在调用时可以选择使用:
代码语言:javascript复制val person: Person? = null
// 安全调用
person?.age = 18
// 强行调用
person!!.name = "kotlin"
使用?调用符,就算person是null的也不会出现空指针了,相当于Java中的判空了。当然如果你能确认person不会为空,可以使用!!强行调用符
1.5 lateinit关键字
代码语言:javascript复制lateinit var person: Person
person = Person()
我们总有场景在声明的时候不知道赋什么值,在后面才去赋值的场景,那么就可以使用lateinit关键字。但是只能在以下场景下使用:
- var声明的变量
- lateinit修饰的变量不可空、不能是基本数据类型、不能有初始值
- 构造器中初始化的变量不需要使用lateinit关键字
1.6 类型判断
代码语言:javascript复制if(p is Person) {
p.age = 20
}
val man: Man = Person()
val per: Person = man as Person
is关键字类似于Java中的instanceof,判断是否是什么类型,判断不是什么类型可用!is,可以看到kotlin有个小优化,就是p在条件成立时,不需要再强转了,直接被认为是Person的类型,进而可以使用Person的API。当你真的需要强转时可以使用as和as?关键字,带?的在强转失败时并不会抛异常,而是返回一个null值
1.7 获取class对象
代码语言:javascript复制// Person.kt
Person::class
// Man.java
Man::class.java
区别于Java,kotlin要兼容Java,所以获取Java的class和kotlin的class略有不同,kotlin的class使用::class,而在kotlin中获取Java的class可以使用::class.java
1.8 setter和getter
代码语言:javascript复制class Person {
var age: Int? = null
}
// 等价于
class Person {
var age: Int? = null
get() {
return field
}
set(value) {
field = value
}
}
kotlin在声明非private的属性时,会默认生成对应的公开的set和get方法,当你在Java中访问时必须:
代码语言:javascript复制Person p = new Person();
p.setAge(20);
不过如果你就要直接访问age属性也是可以的,使用@JvmField注解:
代码语言:javascript复制// kotlin
class Person: Any {
// kotlin构造函数使用constructor关键字
constructor()
// 加上这个注解,编译器只会生成一个public的属性,而不生成set和get方法
@JvmField var age: Int = 19
}
// java
public class Test {
private void some() {
Person p = new Person();
p.age = 20;
}
}
1.9 数组
代码语言:javascript复制open class Person {
constructor(age: Int)
var age: Int = 0
fun test() {
// 会有装箱拆箱的操作,会影响性能
val ages = arrayOf(14, 15, 16)
// 基本数据类型使用对应的函数,比如intArrayOf()函数避免拆装箱的过程
val ages2 = intArrayOf(14, 15, 16)
}
}
可以使用arrayOf()来创建数组。对于基本数据类型优先使用对应的函数进行创建。
1.10 静态函数和属性
代码语言:javascript复制// 方法在类的外面【包级函数】或者叫【顶层函数】
fun getSomething(): Int {
return 0
}
class Person {}
// 在Java中使用类名 Kt后缀直接访问
PersonKt.getSomething();
// 在kotlin文件中调用更加方便,只需要导包,不需要加类名
// 但是这种方式并不有利于阅读,会和类中的函数搞混淆
getSomething()
可以看到我们可以直接在文件里面声明函数,然后通过类名 Kt的方式直接调用。这种叫包级函数
代码语言:javascript复制object Person {
fun getSomething(): Int {
return 0
}
}
// kotlin中调用
Person.getSomething()
// java中调用
Person.INSTANCE.getSomething();
其实使用object创建类的时候,默认会生成一个单例对象,当我们使用类名来直接调用的时候,其实是通过默认的单例对象进行调用的。本质上和我们java中的静态方法还是不同的。
代码语言:javascript复制class Person {
companion object {
fun getSomething(): Int {
return 0
}
}
}
// kotlin
Person.getSomething()
// java,好麻烦,但是可以使用注解@JvmStatic来让编译器编译成静态的
Person.Companion.getSomething();
// java 使用注解后就可以在Java中直接调用了
Person.getSomething();
使用companion object(伴生对象)的方式相当于有一个内部类的单例对象,这些通过kotlin的字节码反编译成Java文件就可以看出来。看起来比直接使用static关键字麻烦多了,那kotlin为啥要去掉static这个关键字呢?那得问当初设计kotlin语言的人了,从面向对象的角度来说,这么设计的确更符合万物皆对象的理念,因为static只跟类有关,而不是和对象有关。
所以,我们可以看出来使用object貌似和创建默认对象有关系,不错,比如匿名内部类(本质上就是创建一个对象)
代码语言:javascript复制 var view = window.decorView
fun test() {
view.setOnClickListener (object : View.OnClickListener{
override fun onClick(v: View?) {
}
})
}
// 当然可以简写成下面这样
fun test() {
view.setOnClickListener {
}
}
1.11 小技巧
可以使用 ${} 来做字符串模板:
代码语言:javascript复制val age = 18
val info = "我是一个${age}岁的帅哥"
支持多行字符串,使用三个引号""":
代码语言:javascript复制 val info = """
hhahha
jaa
sdfjdkjs
jsafjs
""".trimIndent()
判断数据范围和switch的使用:
代码语言:javascript复制// 如果年龄在10到30(包括30)
if(age in 10..30)
// 使用when取代Java中的switch,并且是支持表达式的
when(age) {
18->{
}
19->{
}
in 20..30-> {
}
}
在 Java 中通过 「 类名.this 例如 Outer.this 」 获取目标类引用 在 Kotlin中通过「this@类名 例如this@Outer」获取目标类引用