标签归档:kotlin

Java 类成员执行顺序

  1. 如果类还没有被加载:
    1. 先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关
    2. 执行子类的静态代码块和静态变量初始化
    3. 执行父类的实例变量初始化(例如:int a; 初始化就是0,引用类型就是null)
    4. 执行父类的构造函数
    5. 执行子类的实例变量初始化(例如:int a; 初始化就是0,引用类型就是null)
    6. 执行子类的构造函数
  2. 如果类已经被加载:
    1. 则静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关的变量初始化和构造方法

参考 java 中类初始化,构造方法,静态成员变量,静态块的加载顺序

Kotlin 笔记

基础语法

list

  1. list.indices list 的 index
  2. list.lastIndex list 的 最后一个 index
  3. list.size list 的大小
  4. for((index, value) in array.withIndex()){…}

null

  1. ?. if not null eg: println(files?.size)
  2. ?. ?: if not null and else eg: println(files?.size ?: "empty")
  3. ?: if null eg: val email = data ?: throw IllegalStateException("Email is missing!")
  4. ?.let if not null eg: data?.let{…}
  5. ?.let ?: if not null and else

编码习惯

  1. 冒号 类型和超类型之间的冒号前有一个空格,实例和类型之间的冒号前没有空格

数字类型

  1. Int Float 4*8
  2. Long Double 8*8 默认 Double
  3. Short 2*8
  4. Byte 1*8

数字装箱

数字装箱不保留同一性(=),保留相等性(

显式转换

较小类型不能隐式转换为较大的类型,如 Int 不能转换为 Long,但可以显示转换。如 toInt()

位运算

用中缀方式调用的命名函数,仅适用于 Int 和 Long

  1. shl – 有符号左移
  2. shr – 有符号右移
  3. ushr – 无符号右移
  4. and – 与
  5. or – 或
  6. xor – 异或
  7. inv – 非

字符类型

  1. Char 不能当数字,但可以显示转换 toInt()
  2. 单引号表示 'a'、'0'、'P'
  3. 反斜杠转义 \t、\b、"、\、$

布尔类型

  1. Boolean true false

数组类型

  1. 数组是不型变的,所以不可以把 Array 赋值给 Array,但可以使用 Array(类型投影)
  2. 无装箱开销的原声类型数组:ByteArray、ShortArray、IntArray 等,和 Array 没有继承关系

字符串

  1. 双引号,可以包含转义 "Hello, world!\n"
  2. 三引号,不包含转义,可以包含任何字符
  3. 双引号和三引号都支持字符串模板,要在三引号中表示 \( 可以用:""" \){'$'} """

  1. 不声明包的在无名字的默认包

标签

  1. 声明 标识符+@ eg: loop@、a@
  2. 使用 return@loop break@a

  1. 如果类有一个主构造函数,每个次构造函数都要委托给主构造函数,可以直接委托也可以通过别的次构造函数间接委托。
    class Person(val name: String) {
        constructor(name: String, parent: Person) : this(name) {
            parent.children.add(this)
        }
    }
    
  2. 同时继承一个成员的多个实现,需要指定具体类型 super<A>.a()

  3. 可以用抽象成员覆盖非抽象成员

    open class Base {
        open fun f() {}
    }
    
    abstract class Derived : Base() {
        override abstract fun f()
    }
    
  4. Kotlin 中没有静态方法

接口

  1. 接口中定义的属性,要么是抽象的,要么需要提供访问器实现,不能有初始化器(直接赋值)

扩展函数

  1. 扩展函数的调用取决于声明扩展函数时的类型,而非传入的接受者类型
  2. 扩展函数和成员函数签名相同时,取成员函数
  3. 可以为可空的接收者类型定义扩展,然后在函数体内进行检测

扩展属性

  1. 扩展属性的行为只能由 get、set 定义,不能有初始化器

密封类 sealed

  1. 密封类的子类必须在同一个文件中声明
  2. 密封类的子类的子类可以在任何位置声明
  3. 不允许有非 private 的构造函数

泛型

  1. out 型变 只可以被生产
  2. in 逆型变 只可以被消费

对象表达式 VS 对象声明

  1. 对象表达式用来创建匿名类的对象,比如注册 View 的点击事件 object : SuperClass
  2. 对象声明用于创建一个单例模式的对象,object A { fun aa() {} }

伴生对象

  1. 类内部的对象声明用 companion 标记
  2. 伴生对象的成员可以通过类名来引用,看起来类似于静态成员,运行时仍然是真实对象的实例

对象表达式和对象声明的区别

  1. 对象表达式在使用的地方立即执行
  2. 对象声明在第一次访问时延迟初始化
  3. 伴生对象在类被加载时初始化

委托

  1. 类委托 class Derived(b: Base) : Base by b
  2. 延迟属性 by lazy,默认包含同步锁 synchronized
  3. 可观察属性 by Delegates.observable(默认值){被赋值的属性, old, new -> …}
  4. 映射属性 by map, val 需要 Map,var 需要 MutableMap

函数

  1. 函数的参数必须有显示类型,即使有默认值
  2. 有代码块的函数必须显示指定返回类型,除非返回 Unit
  3. 可变数量的参数 vararg a: T,伸展操作符 *a

中缀表示法

  1. infix fun Int.shl(x: Int): Int
  2. 中缀函数只有一个参数
  3. 1 shl 2 等同于 1.shl(2)

尾递归

  1. tailrec fun a
  2. 递归函数容易出现堆栈溢出
  3. 尾递归函数必须将其自身的调用作为走后一个操作

lambada

  1. 被大括号包围
  2. 如果 lambada 是最后一个参数,可以在圆括号外指定
  3. 如果 lambada 的参数只有一个,用 it
  4. 如果有未使用的参数,用下划线表示:map.forEach {_, value -> print("$value")}
  5. 如果 lambada 的返回类型不是 Unit,那么最后一个表达式即其返回值

匿名函数

  1. 没有函数名字的函数声明
  2. 匿名函数在圆括号内传递
  3. 匿名函数的 return 从匿名函数返回,lambada 的 return 从包含它的函数返回

带接收者的含数字面值

  1. sum : Int.(other: Int) -> Int

内联函数

  1. inline
  2. 会导致生成的代码增加,但会在性能上有所提升

解构

  1. (a, b) 对应 component1(), component2()

集合

  1. List 不可变,MutableList 可变
  2. 。。。