〇、前言
在2017年的Google开发者大会上Google引入了新的Android开发语言Kotlin,2019年的开发者大会上Google 更进一步,宣布Kotlin Frist。伴随的Google的推动,这几年越来越多的Android开发从Java转为Kotlin,一些著名的三方库(如Okhttp)也在采用Kotlin重写。所以是时候总结一下Kotlin的学习笔记了,以期温故而知新。我的学习路线主要是按照《第三行代码》进行的的,所以笔记也以《第三行代码》为主。
一、Kotlin语言简介
Kotlin是由JetBrains公司开发与设计的,2016年Kotlin发布了1.0正式版。
1、为什么可以使用Kotlin语言来替代Java语言进行Android应用程序开发呢?
编程语言可以分为编译型语言和解释型语言,其中Java属于解释型语言:Java代码编译之后生成的并不是计算机可识别的二进制文件,而是.class文件,.class文件只有Java虚拟机才能识别,而Java虚拟机担当的其实就是解释器的角色,它会在程序运行时将编译后的class文件解释成计算机可识别的二进制数据后再执行。
因为Java虚拟机并不直接和你编写的Java代码打交道,而是和编译之后生成的.class文件打交道,Kotlin代码也是编译成同样规格的class文件。而Java虚拟机不关心class文件是从Java编译来的,还是从Kotlin编译来的,只要是符合规格的class文件,它都能识别。也正是这个原因,我们可以使用Kotlin语言来替代Java语言进行Android应用程序开发。
2、Kotlin的优势:
- Kotlin的语法更加简洁,对于同样的功能,使用Kotlin开发的代码量可能会比使用Java开发的减少50% 甚至更多。
- Kotlin的语法更加高级,相比于Java比较老旧的语法,Kotlin增加了很多现代高级语言的语法特性,使得开发效率大大提升。
- Kotlin在语言安全性方面下了很多工夫,几乎杜绝了空指针这个全球崩溃率最高的异常。
- Kotlin和Java是100%兼容的。Kotlin可以直接调用使用Java编写的代码,也可以无缝使用Java第三方的开源库。这使得Kotlin在加入了诸多新特性的同时,还继承了Java的全部财富。
3、运行Kotlin代码
- 使用IntelliJ IDEA。在IntelliJ IDEA里直接创建一个Kotlin项目,就可以独立运行Kotlin代码了。
- 在线运行Kotlin代码。JetBrains专门提供了一个可以在线运行Kotlin代码的网站。
- 使用Android Studio。虽然Android Studio只能创建Android项目,不能创建Kotlin项目。但是我们可以打开一个Android项目,在里面编写一个Kotlin的main()函数,也可以独立运行Kotlin代码。
方法:New→Kotlin File/Class,在弹出的对话框中输入Name。对话框默认选中的类型是File,File通常是用于编写Kotlin顶层函数和扩展函数的(比如编写main()函数);选择Class类型表示创建一个类。
注意,Kotlin每一行代码的结尾不用加分号。
二、变量
1、Kotlin中定义一个变量,只允许在变量前声明两种关键字:val 和 var。
- val(value的简写)用来声明一个不可变的变量,这种变量在初始赋值之后就再也不能重新赋值,对应Java中的final变量。
- var(variable的简写)用来声明一个可变的变量,这种变量在初始赋值之后仍然可以再被重新赋值,对应Java中的非final变量。
与Java不同是因为Kotlin拥有出色的类型推导机制。
val a = 10 //Kotlin拥有类型推导机制,这里a就会被自动推导成整型变量
val b: Int = 10 //显式地声明了变量b为Int类型,此时就不会再尝试进行类型推导了
2、Kotlin完全抛弃了Java中的基本数据类型,全部使用了对象数据类型,即Kotlin中没有基本数据类型。Java和Kotlin数据类型对照如下:
Java基本数据类型 | Kotlin对象数据类型 | 数据类型说明 |
---|---|---|
|
| 整型 |
|
| 长整型 |
|
| 短整型 |
|
| 单精度浮点型 |
|
| 双精度浮点型 |
|
| 布尔型 |
|
| 字符型 |
|
| 字节型 |
三、函数
Java中常称为方法,在Kotlin中叫函数更普遍一些,它们其实就是同一个概念,其中函数翻译自function,方法翻译自method。Kotlin中定义函数的语法规则如下:
fun methodName(param1: Int, param2: Int): Int {
return 0
}
与Java不同:fun
(function的简写)是定义函数的关键字,无论你定义什么函数,都一定要使用fun
来声明。参数的声明格式是“参数名: 参数类型
”
Kotlin函数的语法糖:当一个函数中只有一行代码时,Kotlin允许我们不必编写函数体,可以直接将唯一的一行代码写在函数定义的尾部,中间用等号连接即可。
/**
* Kotlin函数的语法糖:
* 当一个函数中只有一行代码时,Kotlin允许我们不必编写函数体,可以直接将唯一的一行代码写在函数定义的尾部,中间用等号连接即可。
*/
fun largerNumber(num1: Int, num2: Int): Int {
return max(num1, num2)
}
//运用Kotlin的语法糖,上述代码可以简化为:
fun largerNumber(num1: Int, num2: Int): Int = max(num1, num2)
//运用Kotlin的类型推导机制,上述代码可以进一步简化为:
fun largerNumber(num1: Int, num2: Int) = max(num1, num2)
四、面向对象编程
不管你有没有对象,同java一样Kotlin也是面向对象的。
1、类与对象(封装)
与Java一致,Kotlin中也是使用class
关键字来声明一个类。但是在创建对象时去掉了new
关键字,Kotlin创建对象的方式如下:
val p = Person()
这样的写法看起来是调用了一个方法并将返回值赋值给声明的变量,但细想就是调用了一个方法啊,只是这个方法是构造函数而已。Kotlin本着最简化的设计原则,将诸如new
、行尾分号这种不必要的语法结构都取消了。
2、继承
Kotlin中想要让子
类继承父类,需要两步:
①使父类可以被继承,给父类加上open
关键字。
在Kotlin中任何一个非抽象类默认都是不可以被继承的,相当于Java中给类声明了final
关键字。Effective Java这本书中明确提到,如果一个类不是专门为继承而设计的,那么就应该主动将它加上final
声明,禁止它可以被继承,Kotlin的设计显然是遵循了这条编程规范直接默认所有非抽象类都是不可以被继承的。要让类可以被继承,需要在类的前面加上open
关键字。
当然抽象类默认是可以被继承的,否则就没有意义了(Kotlin中的抽象类和Java中并无区别)。
②继承的关键字由Java中的extends
变成了在Kotlin中的冒号。如:
class Student : Person() {
var sno = ""
var grade = 0
}
需要注意的是父类后面带有括号表示子类的主构造函数调用了父类中的主构造函数,因为子类的构造函数必须调用父类的构造函数。
3、构造函数:Kotlin将构造函数分成了两种:主构造函数和次构造函数。
①主构造函数:主构造函数的特点是没有函数体,直接定义在类名的后面。主构造函数将会是最常用的构造函数,每个类默认都会有一个不带参数的主构造函数,当然也可以显式地给它指明参数如下:
class Student(val sno: String, val grade: Int) : Person() {
//Person类后面的一对空括号表示Student类的主构造函数在初始化的时候会调用Person类的无参数构造函数
//即使在无参数的情况下,这对括号也不能省略。
}
作为补充所有主构造函数中的逻辑都可以写在init
结构体里面。
class Student(val sno: String, val grade: Int) : Person() {
init {
println("sno is " + sno)
println("grade is " + grade)
}
}
在主构造函数中声明成val
或者var
的参数将自动成为该类的字段,如果主构造函数中的参数前面不加任何关键字,它的作用域就仅限定在主构造函数当中(相当于形式参数)。
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
...
}
②次构造函数:次构造函数是通过constructor
关键字来定义的,是有函数体的。任何一个类只能有一个主构造函数,但是可以有多个次构造函数。次构造函数也可以用于实例化一个类。
Kotlin规定,当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)。
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
constructor(name: String, age: Int) : this("", 0, name, age) {
}
constructor() : this("", 0) {
}
}
Kotlin允许类中只有次构造函数,没有主构造函数。当一个类没有显式地定义主构造函数且定义了次构造函数时,它就是没有主构造函数的。
//首先Student类的后面没有显式地定义主构造函数,同时又因为定义了次构造函数,所以现在Student类是没有默认主构造函数的。
//那么既然没有主构造函数,继承Person类的时候也就不需要再加上括号了。
class Student : Person {
constructor(name: String, age: Int) : super(name, age) {
}
}
4、接口(多态)
①Kotlin同Java一样,是单继承结构的语言,任何一个类最多只能继承一个父类,但是却可以实现任意多个接口。接口的关键字都是interface。
②Java中继承使用的关键字是extends
,实现接口使用的关键字是implements
,而Kotlin中统一使用冒号,中间用逗号进行分隔。另外接口的后面不用加上括号,因为它没有构造函数可以去调用;
③Kotlin中使用override
关键字来重写父类或者实现接口中的函数;
④同JDK 1.8一样,Kotlin允许对接口中定义的函数进行默认实现。如果接口中的一个函数拥有了函数体,这个函数体中的内容就是它的默认实现(Java中需要添加default关键字)。子类可以自由选择实现或者不实现默认实现函数,不实现时就会自动使用默认的实现逻辑。
5、函数的可见性修饰符
Java和Kotlin函数可见性修饰符对照表
修饰符 | Java | Kotlin |
---|---|---|
| 所有类可见 | 所有类可见(默认) |
| 当前类可见 | 当前类可见 |
| 当前类、子类、同一包路径下的类可见 | 当前类、子类可见 |
| 同一包路径下的类可见(默认) | 无 |
| 无 | 同一模块中的类可见 |
6、数据类
data:当在一个类前面声明了data
关键字时,就表明你希望这个类是一个数据类,Kotlin会根据主构造函数中的参数帮你将equals()
、hashCode()
、toString()
等方法自动生成。
7、单例类
虽然Java中的单例实现并不复杂,但是Kotlin做得更好,它将一些固定的、重复的逻辑实现隐藏了起来,只暴露给我们最简单方便的用法。在Kotlin中创建一个单例类的方式极其简单,只需要将class
关键字改成object
关键字即可。在Kotlin中我们不需要私有化构造函数,也不需要提供getInstance()
这样的静态方法,只需要把class
关键字改成object
关键字,一个单例类就创建完成了。
参考文档:《Kotlin的面向对象编程,深入讨论继承写法的问题》