Kotlin 笔记

中文站
Github
菜鸟工具-在线编译

Kotlin 设计精髓

  1. 空值安全
  2. 扩展函数
  3. 扩展属性
  4. 属性代理
  5. 运算符
  6. 解构
  7. 协程

构造函数 (constructor)

Koltin 中的类可以有一个 主构造器,以及一个或多个次构造器,主构造器是类头部的一部分,位于类名称之后:

1
class Person constructor(firstName: String) {}

如果主构造器没有任何注解,也没有任何可见度修饰符,那么constructor关键字可以省略。

1
2
class Person(firstName: String) {
}

主构造器

主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用 init 关键字作为前缀。

1
2
3
4
5
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}

次构造函数

类也可以有二级构造函数,需要加前缀 constructor:

1
2
3
4
5
class Person { 
constructor(parent: Person) {
parent.children.add(this)
}
}

如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:

1
2
3
4
5
class Person(val name: String) {
constructor (name: String, age:Int) : this(name) {
// 初始化...
}
}

如果一个非抽象类没有声明构造函数(主构造函数或次构造函数),它会产生一个没有参数的构造函数。构造函数是 public 。如果你不想你的类有公共的构造函数,你就得声明一个空的主构造函数:

1
2
class DontCreateMe private constructor () {
}

抽象类

抽象是面向对象编程的特征之一,类本身,或类中的部分成员,都可以声明为abstract的。抽象成员在类中不存在具体的实现。
注意:无需对抽象类或抽象成员标注open注解。

1
2
3
4
5
6
7
open class Base {
open fun f() {}
}

abstract class Derived : Base() {
override abstract fun f()
}

嵌套类

1
2
3
4
5
6
7
8
9
10
11
class Outer {                  // 外部类
private val bar: Int = 1
class Nested { // 嵌套类
fun foo() = 2
}
}

fun main(args: Array<String>) {
val demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
println(demo) // == 2
}

内部类

内部类使用 inner 关键字来表示。
内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Outer {
private val bar: Int = 1
var v = "成员属性"
/**嵌套内部类**/
inner class Inner {
fun foo() = bar // 访问外部类成员
fun innerTest() {
var o = this@Outer //获取外部类的成员变量
println("内部类可以引用外部类的成员,例如:" + o.v)
}
}
}

fun main(args: Array<String>) {
val demo = Outer().Inner().foo()
println(demo) // 1
val demo2 = Outer().Inner().innerTest()
println(demo2) // 内部类可以引用外部类的成员,例如:成员属性
}

为了消除歧义,要访问来自外部作用域的 this,我们使用this@label,其中 @label 是一个 代指 this 来源的标签。

这里说下嵌套类内部类的区别:

  1. 创建对象的区别

    1
    2
    var demo = Outter.Nested()// 嵌套类,Outter后边没有括号
    var demo = Outter().Inner();// 内部类,Outter后边有括号
  2. 引用外部类的成员变量的方式不同
    嵌套类需要创建对象:

    1
    2
    3
    4
    5
    6
    7
    8
    class Outer {                  // 外部类
    private val bar: Int = 1
    class Nested { // 嵌套类
    var ot: Outer = Outer()
    println(ot.bar) // 嵌套类可以引用外部类私有变量,但要先创建外部类的实例,不能直接引用
    fun foo() = 2
    }
    }

    内部类使用this@ 不需要创建对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Outer {
    private val bar: Int = 1
    var v = "成员属性"
    /**嵌套内部类**/
    inner class Inner {
    fun foo() = bar // 访问外部类成员
    fun innerTest() {
    var o = this@Outer //获取外部类的成员变量
    println("内部类可以引用外部类的成员,例如:" + o.v)
    }
    }
    }

对象(判空)

NULL检查机制

1
2
3
4
5
6
7
8
//类型后面加?表示可为空
var age: String? = "23"
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1

?: (Eivis)

1
val l = b?.length ?: -1

如果 ?: 左侧表达式非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式。 请注意,当且仅当左侧为空时,才会对右侧表达式求值
相当于:

1
val l: Int = if (b != null) b.length else -1

操作符

apply

它是一个内联扩展函数
它把 this 作为参数
它返回了 this(它自己)

1
2
3
webView.setting?.apply{
//todo
}

let

obj不等于null执行函数体, 等于null则不执行
在函数块内可以通过 it 指代该对象。返回值为函数块的最后一行或指定return表达式。

1
2
3
4
val a = webView.setting?.let {
it.javaScriptEnabled = true
it.databaseEnabled = true
}

run

用法一:
返回值为函数块最后一行,或者指定return表达式

1
2
3
4
val a = run {
println("run")
return@run 3
}

用法二:
在函数块内可以通过 this 指代该对象。返回值为函数块的最后一行或指定return表达式。

1
2
3
4
val a = webView.setting?.run {
javaScriptEnabled = true
databaseEnabled = true
}

also

在函数块内可以通过 it 指代该对象。返回值为该对象自己

1
2
3
val a = webView.setting?.also {
it.javaScriptEnabled = true
}

with

with函数和前面的几个函数使用方式略有不同,因为它不是以扩展的形式存在的。它是将某对象作为函数的参数,在函数块内可以通过 this 指代该对象。返回值为函数块的最后一行或指定return表达式

1
2
3
4
val a = with(webView.setting) {
javaScriptEnabled = true
databaseEnabled = true
}

with相比let,run 空安全处理

1
2
3
4
val a = with(webView.setting) {
this?.javaScriptEnabled = true
this?.databaseEnabled = true
}

集合操作符(逻辑)

any

判断集合中是否有元素满足某个条件,有则返回true

all

判断集合中的所有元素是否满足某个条件,都满足返回true

count

返回集合中满足某个条件的元素数量

find

查找集合中满足某个条件的一个元素,不存在则返回null

filter

将集合里的元素过滤,并返回过滤后的元素

map

将集合里的元素一一对应转换为另一个元素

flatMap

将集合的元素转换为另外的元素(非一一对应)

max

返回集合中以某个条件排序的最大的元素

min

返回集合中以某个条件排序的最小的元素

sort

根据某个条件对集合元素进行排序

sum

对集合中的元素按照某种规则进行相加

groupBy

对集合中的元素按照某种规则进行组合

partition

根据某种规则将集合中的元素分为两组

fold

对集合的元素按照某个逻辑进行一一累计

其他关键字

vararg

函数的变长参数可以用 vararg 关键字进行标识:

1
2
3
4
5
6
7
8
9
10
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}

// 使用
fun main(args: Array<String>) {
vars(1,2,3,4,5) // 输出12345
}

lambda(匿名函数)

1
2
3
4
5
// 测试
fun main(args: Array<String>) {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 输出 3
}