二、Android-Kotlin语言

182 阅读6分钟

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

类似于swiftprotocol协议。在接口中声明一系列抽象行为,然后由具体的类去实现。

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 可见性修饰符

修饰符JavaKotlin
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里面类似,mapfiltermaxByanyall

单独声明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 。有点类似于IOSlazy 变量。

    val adapter: MsgAdapter by lazy {
        MsgAdapter(msgList)
    }

使用时,在类型后面加 by lazy { }

  • lazy只能对常量val使用,不能修饰变量var
  • lazy加载的时机为第一次调用常量的时候,且只会加载一次

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)
    }