2.1 简介
java是解释性语言,先编译成特殊的class文件,然后在ATR(虚拟机)中解释成计算机可识别的二进制数据,边解释边运行。
同样的,kotlin也是先编译成class文件。
2.2 变量
val: value的简写,声明一个不可变的变量
var: variable的简写,声明一个可变的变量
变量具有类型推导机制。
Kotlin每一行代码的结尾不用加分号。
2.3 函数
fun methodName(param1: Int, param2: Int): Int {
return 0
}
// 语法糖 如果函数体只有一行代码,可以简写
fun largerNumber(num1: Int, num2: Int) = max(num1, num2)
2.4 程序的逻辑控制
// when 相当于switch
fun getScore(name: String): Int {
var score = 0
when (name) {
"Tom" -> score = 10
"Tom1" -> score = 10
else -> score = 0
}
}
fun checkNumber(num: Number) {
when (num) {
is Int -> {
println("number is Int")
}
is Double -> {
println("number is Double")
}
else -> {
println("number not support")
}
}
}
区间:val range = 0..10 用数学的方式表达就是 [0, 10], 这是一个闭区间。从0到10,包含0和10。
// for 循环
for (i in 0..10) {
println(i)
}
for (i in 0 until 10 step 2) {
println(i)
}
for (i in 10 downTo 1) {
println(i)
}
val range = 0 until 10 左闭右开的区间, [0, 10)。从0到9。
step: 步长,i + 2
如果想创建一个降序的区间,使用downTo关键字
2.5 面向对象编程 class
class Person {
var name = ""
var age = 0
fun eat() {
println("$name is eating. He is $age years old.")
}
}
// 使用
var p = Person()
p.name = "Jack"
p.age = 20
p.eat()
继承
class Student: Person() {
var sno = ""
var grade = 0
}
任何一个类只能有一个主构造函数,但是可以有多个次构造函数。
主构造函数是类头的一部分,通常在类名后面声明。
次构造函数用 constructor声明,次构造函数必须直接或者间接调用主构造函数。
// 主构造函数(name: String, age: Int)
class Student(name: String, age: Int): Person() {
var sno = ""
var grade = 0
// 次构造函数
constructor(grade: Int): this("Jack", 20) {
this.sno = "001"
this.grade = grade
}
// 次构造函数
constructor(): this(100) {
}
}
2.6 接口 interface
类似于swift的protocol协议。在接口中声明一系列抽象行为,然后由具体的类去实现。
interface Study {
fun readBooks()
fun doHomework()
// 接口的默认实现
fun play() {
println("play default implementation.")
}
}
class Student(name: String, age: Int): Person(), Study {
var sno = ""
var grade = 0
// ...
// Study
override fun readBooks() {
println("$name is reading.")
}
override fun doHomework() {
println("$name is dong homework.")
}
}
Kotlin中使用override关键字来重写父类或者实现接口中的函数。
2.7 可见性修饰符
| 修饰符 | Java | Kotlin |
|---|---|---|
| public | 所有类可见 | 所有类可见(默认) |
| private | 当前类可见 | 当前类可见 |
| protected | 当前类、子类、同一包路径下的类可见 | 当前类、子类可见 |
| default | 同一包路径下的类可见(默认) | 无 |
| internal | 无 | 同一模块中的类可见 |
2.8 数据类
使用data 关键字。表明这是一个数据类,Kotlin会根据主构造函数中的参数帮你将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成。
data class Cellphone(val brand: String, val price: Double) {
}
2.9 单例类
只需要将class关键字改为object关键字即可。
object Singleton {
fun walk() {
println("singleton is walking")
}
}
// 使用
Singleton.walk()
2.10 高阶函数和Lambda
高阶函数和Swift里面类似,map、filter、maxBy、any、all
单独声明lanbda: {参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}
any: 判断集合中是否至少存在一个元素满足条件
all: 判断集合中是否所有元素都满足条件
都返回Boolean值
2.11 可空类型系统
和Swift类似
fun doStudy(study: Study?) {
study?.readBooks()
study?.doHomework()
}
在类型后面跟 ? 表示该变量可能为空。
使用的时候:
?. 操作符:不为空是正常调用,为空时什么都不做
?: 操作符:如果左边不为空就返回左边,如果左边为空就返回右边
!! 操作符:强制解析,如果为空则会异常
let 函数,Kotlin中的标准函数,将原始调用对象作为参数传递到Lambda表达式中。
obj.let { obj2 ->
// 编写具体的业务逻辑 obj2和obj是一个对象
}
fun doStudy(study: Study?) {
study?.let {
it.readBooks()
it.doHomework()
}
}
2.12 字符串内嵌表达式
使用${}结构表达式
"hello, ${obj.name}. nice to meet you!"
当表达式中仅有一个变量的时候,可以省略两边的大括号
"hello, $name. nice to meet you!"
2.13 函数的参数默认值
参数默认值,使用可以使用键值对传参。
fun printParams(num: Int = 100, str: String) {
println("num is $num , str is $str")
}
fun main() {
printParams(str = "world")
}
2.14 运算符 is 和 !is
is运算符类似于java中的 instanceof 关键字的用法。is运算符可以检查对象是否与特定类型兼容,就是是否是该类型或者子类型或者遵守了某个接口interface。返回值是Boolean类型。
!is就是它的否定形式。
2.15 运算符 as 和 as?
as用于显示类型转换。如果要转换的类型与指定的类型兼容,转换就会成功;不兼容报异常。
as?在不兼容的时候不会报异常,会返回null值。
父类是禁止转换为子类型的。
2.16 延迟加载-lateinit
关键字:lateinit
会告诉编译器晚会会对这个变量进行初始化。
lateinit var adapter: MsgAdapter
- 只能修饰变量
var,不能修饰常量val - 不能对可空类型使用
- 不能对
java基本类型使用(Double、Int、Long) - 在调用
lateinit修饰的变量时,如果还没初始化,则会抛出未初始化异常
另外,我们还可以判断一个全局变量是否已经完成了初始化
if (!::adapter.isInitialized) {
adapter = MsgAdapter(msgList)
}
语法:::adapter.isInitialized
判断变量是否已经初始化。
2.17 延迟加载-lazy
关键字:lazy 。有点类似于IOS的 lazy 变量。
val adapter: MsgAdapter by lazy {
MsgAdapter(msgList)
}
使用时,在类型后面加 by lazy { } 。
lazy只能对常量val使用,不能修饰变量varlazy加载的时机为第一次调用常量的时候,且只会加载一次
2.18 泛型
类似Swift泛型
class MyClass<T> {
fun method(param: T): T {
return param
}
}
// 调用时指定泛型类型
val a = MyClass<Int>()
val res = a.method(123)
也可以定义泛型方法
fun <M>method2(param: M) {
}
给泛型加限制
fun <M: Int>method3(param: M) {
}
在默认情况下,所有的泛型都是可以指定成可空类型的,这是因为在不手动指定上界的时候,泛型的上界默认是Any?。而如果想要让泛型的类型不可为空,只需要将泛型的上界手动指定成Any就可以了。
2.19 vararg参数类型
可以接受任意多个同样类型的参数
fun max(vararg nums: Int): Int {
var maxNum = Int.MIN_VALUE
for (num in nums) {
maxNum = kotlin.math.max(maxNum, num)
}
return maxNum
}
val a = 10
val b = 15
val c = 5
val largest = max(a, b, c)
2.20 DSL-构建专有的语法结构
class Dependency {
val libraries = ArrayList<String>()
fun implementation(lib: String) {
libraries.add(lib)
}
}
fun dependencies(block: Dependency.() -> Unit): List<String> {
val dependency = Dependency()
dependency.block()
return dependency.libraries
}
val libs = dependencies {
implementation("com.hello.world:library:1.0.0")
implementation("com.hello.room:library:1.0.0")
}
for (lib in libs) {
println(lib)
}