中文教程

英文教程

kotlin 文档

kotlin 对比 java

kotlin 没有 new ,所以匿名内部类 用 object: ,类似代码如下

1
setOnClickListener(new View.OnClickListener() {})
1
setOnClickListener( object : View.OnClickListener{})

kotlin 没有 static 有三种方式来写
顶层函数,直接新建 File
用单例 object 修饰的类
伴生对象 在类中写 companion object

java 中 Float 是包装类,属于对象, kotlin 的 Float 是基本类型,和 java 对应的应该是 Float?

intArrayOf(1,2) 和 arrayOf(1,2) 区别在于 intArrayOf 声明了数组的类型,就少了拆箱装箱的步骤

构造函数

1
2
3
4
    //构造函数 this 和 super 写法与 java 对比
    constructor(context: Context) : this(context, null) {}

    constructor(context: Context, text:String?) : super(context, text) {}
1
2
3
4
5
6
7
    public TestClass(Context context) {
        this(context, "");
    }

    public TestClass(Context context, String text) {
        super(context, text);
    }

集合

List 类似数组,是一个有序集合 ,Set 无重复元素,这两个都继承自 Collection。map 键值对

List

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    //在 Kotlin 中,MutableList 的默认实现是 ArrayList, 可以将其视为可调整大小的数组
    //需要操作如添加删除则写成 mutableListOf 
    val intArray = intArrayOf(1, 2, 3, 4, 5)

    //for (i in 0 until intArray.size) for (i in 0.until(intArray.size))
    for (i in intArray.indices) {
        println(intArray[i])
    }

    for (item in intArray) {
        println(item)
    }

    intArray.forEach { println(it) }

    for ((index, value) in intArray.withIndex()) {
        println("the element at $index is $value")
    }

    //取能被2整除的
    val filterArray = intArray.filter { it % 2 == 0 }
    //filterIndexed 带数组下标,以下是过滤掉第一个元素, index 是下标, any 是值
    val filterArray = intArray.filterIndexed { index, any -> index == 0 }
    //取前两个的 takeLast 取后边的
    val takeArray = intArray.take(2)
    //取丢弃前两个的 dropLast 丢弃后边的
    val dropArray = intArray.drop(2)
    //结果 (1,2,3)
    val sliceArray = intArray.slice(0..2)
    //结果 (1,3,5)
    val sliceStepArray = intArray.slice(0..4 step 2)
    //随机取一个
    intArray.random()

Set

1
2
3
4
    val numbers = setOf(1, 2, 3, 4)
    val numbersBackwards = setOf(4, 3, 2, 1)
    println("The sets are equal: ${numbers == numbersBackwards}")//The sets are equal: true
    //mutableSetOf 对应 LinkedHashSet 保留元素插入的顺序。hashSetOf 对应 HashSet 不声明元素的顺序

Map

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)    
    val anotherMap = mapOf("key2" to 2, "key1" to 1, "key4" to 1, "key3" to 3)
    println("The maps are equal: ${numbersMap == anotherMap}")//The maps are equal: true
    1 in numbersMap.values//是否包含值为1
    numbersMap.containsValue(1)//同上

    //操作 map
    val numbersMap = mutableMapOf("one" to 1, "two" to 2)
    numbersMap.put("three", 3)
    numbersMap["one"] = 11
    //mutableMapOf 有序 hashMapOf 无序

companion object

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//在 kotlin 中调用直接 TestClass.mContext ,在 Java 中 GameMySaveListActivity.Companion.getMContext();
//加了 @JvmStatic 后可以写成 TestClass.getMContext();
//再加 @get:JvmName("mContext") 就可以和  kotlin 一样 TestClass.mContext;
class TestClass {
    companion object {
        @JvmStatic
        @get:JvmName("mContext")
        lateinit var mContext: Context
    }
}

other

1
2
3
4
5
6
    //这种情况会找不到 isInit 所以 init 方法一般可以放最后
    init {
        isInit = false
    }

    var isInit = true
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    //?: 使用
    val text: String? = ""
    //如果 text?.length 空则是 0 < 4 ,不空则 text?.length < 4
    if (text?.length ?: 0 < 4) {

    }
    //相当于
    if (text?.length == null || text.length < 4) {

    }
1
2
3
    //默认会生成一些方法,如果想重写 get set 方法 直接跟在下一行
    lateinit var mContext: Context
        private set
1
2
3
4
5
//:: 创建一个成员引用或者一个类引用
val c = MyClass::class
lateinit var lateString: String
//isInitialized 用来判断 lateinit var 是否初始化
::lateString.isInitialized

as? 用于安全类型转换。

Kotlin 一切都是对象,所有类都有一个共同的超类 Any,对于没有超类型声明的类它是默认超类,kotlin 的类默认是 final ,加 open 后才可继承

kotlin 可以嵌套函数,可以方便子函数可以直接调用父函数的对象,可能对性能有影响

toCollection 是一个扩展函数,用于将一个可迭代对象转换为指定类型的集合。

inline 内联函数

效果相当是复制到调用的地方
一般推荐在入参是函数时使用,可以减少调用栈

密封类

优点 密封类拥有抽象类的灵活,子类可以是任意的类,数据类,对象,普通类,甚至密封类
密封类拥有枚举的限制
子类涵盖所有情况时,使用 when 表达式,不必添加 else 分支

相对 java 有点像可以带参数的枚举, 使用如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
sealed class UIEvent {
    object ShowLoading: UIEvent()
    object HideLoading: UIEvent()
    class ShowData(val message: String): UIEvent()
}


interface ISplashBaseView : IView {
    fun sendEvent(event: UIEvent)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class MainActivity() : BaseActivity(), ISplashBaseView {
    override fun sendEvent(event: UIEvent) {
        when (event) {
            is UIEvent.ShowLoading -> showLoading()
            is UIEvent.HideLoading -> hideLoading()
            is UIEvent.ShowData -> showData(event.message)
        }
    }

    private fun showLoading() {

    }

    private fun hideLoading() {

    }

    private fun showData(message: String) {

    }

    override fun getLayoutResId(): Int {
        return R.layout.activity_main
    }
}

解构声明

1
2
//一个解构声明同时创建多个变量 和 swift 元组类似
val (name, age) = person

为什么有些匿名内部类写法 object : 可以用 lambda省略

如果一个接口只有一个抽象方法(即这个接口是函数式接口或单方法接口),那么可以使用 lambda 表达式或方法引用来代替该接口的实现。
如果一个接口有多个抽象方法,那么必须实例化该接口并重写其中的所有方法,直接使用 lambda 表达式或方法引用是不允许的。
如果一个类是抽象类,那么你必须实现其中的所有抽象方法,否则你的类仍然需要声明为一个抽象类。
如果一个类实现了一个接口,那么该类必须实现该接口中的每一个方法,使用 lambda 表达式或方法引用是不允许的。
如果一个类实现了一个接口但只想使用该接口的某些方法,则可以使用 default 方法、抽象类(包含默认实现)或者抽象的委托类(只委托某些方法),转发该接口的所有方法到这些类,从而避免重复的编码实现。

匿名内部类 比如 new Thread(new Runnable() { … }) 这种写法就是匿名内部类

无符号整形

UByte: 无符号 8 位整数,范围是 0 到 2^8 - 1
还有 UShort UInt ULong