1. 1. 基本类型
    1. 1.1. 类型转换
    2. 1.2. 同一性和相等性
    3. 1.3. 字符串支持模版
  2. 2. 导包出现冲突,支持用 as 做本地重命名
  3. 3. 控制流
    1. 3.1. 基本控制结构(循环,条件)
    2. 3.2. 标签返回与跳转
    3. 3.3. 主构函数、init 初始化块 、次构函数
      1. 3.3.1. 主构函数参数
      2. 3.3.2. 无 new 关键字
    4. 3.4. 继承
      1. 3.4.1. 必须就地初始化
      2. 3.4.2. 默认final , 标注 open 可继承
      3. 3.4.3. 覆盖方法
      4. 3.4.4. 覆盖属性,var 可覆盖val,反之不可
  4. 4. 属性与字段
    1. 4.1. 可变var,只读val
    2. 4.2. 模块与 internal
  5. 5. 扩展
    1. 5.1. 扩展函数(可结合范型)
    2. 5.2. 扩展的分发接收者、扩展接收者
    3. 5.3. 用限定this来解决两个接收者的成员名字冲突
    4. 5.4. 扩展函数
  6. 6. data 标记数据类
  7. 7. copy复制一个对象并改变它的一些属性
  8. 8. 密封类——类似于可保持状态的java枚举
  9. 9. 范型,型变(声明处型变、类型型变)
    1. 9.1. 声明处型变,out 生产者,in 消费者
  10. 10. 对象
    1. 10.1. 匿名类
    2. 10.2. object 关键字对象声明(使得单例模式极为简易)
    3. 10.3. companion 伴生对象
    4. 10.4. 对象表达式和对象声明之间的语义差异
  11. 11. 委托
    1. 11.1. 类委托
    2. 11.2. 属性委托
      1. 11.2.1. 标准属性委托
        1. 11.2.1.1. lazy
        2. 11.2.1.2. observable 和 vetoable
        3. 11.2.1.3. map
  12. 12. 函数 fun
    1. 12.1. 默认参数及其覆写注意项,命名参数解决参数冲突现象
    2. 12.2. 星号操作符以命名形式传入可变变量参数
    3. 12.3. Unit
    4. 12.4. 函数可以在文件顶层声明,并且可嵌套
  13. 13. 其他
    1. 13.1. 限定this
    2. 13.2. 引用相等与结构相等,浮点数相等
    3. 13.3. 空容纳性声明
    4. 13.4. 在条件中检查 null
    5. 13.5. 安全调用符
    6. 13.6. Elvis 操作符
    7. 13.7. !! 操作符
    8. 13.8. filterNotNull 过滤非空元素
    9. 13.9. 异常类,try 表达式,无受检异常
    10. 13.10. 注解、反射(有点绕,先放着用到再看)
    11. 13.11. typealias 类型别名
    12. 13.12. 不一样的 TODO

基本类型

接近Java,但有些不同点要注意。下面列出。

类型转换

没有了隐式转换,必须使用显式转换

同一性和相等性

基本类型装箱不保留同一性,只保留相等性。 如果显示转换过,那么同一性和相等性都失去 。

字符串支持模版

导包出现冲突,支持用 as 做本地重命名

控制流

基本控制结构(循环,条件)

if,else,for,while
when,(index, value) in array.withIndex(),in,step,down to
if 表达式代替三元运算符

标签返回与跳转

#类与继承

主构函数、init 初始化块 、次构函数

主构函数直接跟在类名后面,不带具体函数实现;
如有需要的初始化操作,放在init 初始化块即可;
也可以用 constructor 在类里面定义次构函数,在这里初始化(一般这种是针对不同构造器有不同初始化才放到这里)。注意如存在主构函数,则次构函数必须间接或直接委托主构函数。

主构函数参数

注意,主构造的参数可以在初始化块中使用。它们也可以在类体内声明的属性初始化器中使用.

1
2
3
class Customer(name: String) {
val customerKey = name.toUpperCase()
}

事实上,声明属性以及从主构造函数初始化属性,Kotlin 有简洁的语法:

1
2
3
class Person(val firstName: String, val lastName: String, var age: Int) {
// ……
}

与普通属性一样,主构造函数中声明的属性可以是可变的(var)或只读的(val)。
如果构造函数有注解或可见性修饰符,这个 constructor 关键字是必需的,并且这些修饰符在它前面:

1
class Customer public @Inject constructor(name: String) { …… }

无 new 关键字

调用构造函数就可以创建类的实例

继承

1
2
open class Base(p: Int)
class Derived(p: Int) : Base(p)

必须就地初始化

默认final , 标注 open 可继承

类上的 open 标注与 Java 中 final 相反,它允许其他类从这个类继承。默认情况下,在 Kotlin 中所有的类都是 final, 对应于 Effective Java书中的第 17 条:要么为继承而设计,并提供文档说明,要么就禁止继承。

覆盖方法

显示的 open 和 override。
默认 final 不可继承。
可在子类中用 final 来终止开放的继承权限链。

覆盖属性,var 可覆盖val,反之不可

属性与字段

可变var,只读val

模块与 internal

可见性修饰符,比java的多了internal。
internal可见性修饰符意味着成员在同一个模块中可见。更具体的,一个模块是一组被一起编译的Kotlin文件:
一个 Intellij IDEA 模块;
一个Maven或者Gradle工程;
一组用一个Ant任务编译的文件集合。
个人理解就是类似于在一个项目库里面可见。比如我写了一个开源库,我在库内部可见自己用。提供库给别人接入的时候不给他们用。

扩展

扩展函数(可结合范型)

优先级低于成员函数,
扩展有作用域,要导好包

扩展的分发接收者、扩展接收者

用限定this来解决两个接收者的成员名字冲突

扩展函数

对扩展接收者静态解析,对分发接收者虚拟可继承;该设计的动机

data 标记数据类

copy复制一个对象并改变它的一些属性

密封类——类似于可保持状态的java枚举

范型,型变(声明处型变、类型型变)

(Todo. 范型系列没理解透,有空要重看)

声明处型变,out 生产者,in 消费者

对象

匿名类

object 关键字对象声明(使得单例模式极为简易)

companion 伴生对象

请注意,即使伴生对象的成员看起来像其他语言的静态成员,在运行时他们仍然是真实对象的实例成员,而且,例如还可以实现接口。
在 JVM 平台,如果使用 @JvmStatic 注解,你可以将伴生对象的成员生成为真正的静态方法和字段。

对象表达式和对象声明之间的语义差异

对象表达式是在使用他们的地方立即执行(及初始化)的;
对象声明是在第一次被访问到时延迟初始化的;
伴生对象的初始化是在相应的类被加载(解析)时,与 Java 静态初始化器的语义相匹配。

委托

类委托

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Base {
fun print()
}

class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}

class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).print() // 输出 10
}

属性委托

1
var p: String by Delegate()

标准属性委托

有一些常见的属性类型,虽然我们可以在每次需要的时候手动实现它们, 但是如果能够为大家把他们只实现一次并放入一个库会更好。例如包括:

lazy

延迟属性(lazy properties): 其值只在首次访问时计算;

observable 和 vetoable

可观察属性(observable properties): 监听器会收到有关此属性变更的通知;如果你想能够截获一个赋值并“否决”它,就使用 vetoable() 取代 observable()。 在属性被赋新值生效之前会调用传递给 vetoable 的处理程序。

map

(这个委托的用法和场景还是不太理解,碰到了再来看。。)
把多个属性储存在一个映射(map)中,而不是每个存在单独x的字段中。

函数 fun

默认参数及其覆写注意项,命名参数解决参数冲突现象

极有效率地减少了重载数量。

星号操作符以命名形式传入可变变量参数

(调用 Java 函数时不能使用)
伸展(spread)操作符(在数组前面加 *)

Unit

(为什么要设计一个unit,还不明白)

函数可以在文件顶层声明,并且可嵌套

其他

限定this

引用相等与结构相等,浮点数相等

空容纳性声明

1
2
3
4
var a: String = "abc"
a = null // 编译错误
var b: String? = "abc"
b = null // ok

在条件中检查 null

安全调用符

1
2
//安全调用在链式调用中很有用。例如,如果一个员工 Bob 可能会(或者不会)分配给一个部门, 并且可能有另外一个员工是该部门的负责人,那么获取 Bob 所在部门负责人(如果有的话)的名字,我们写作:
bob?.department?.head?.name

Elvis 操作符

1
2
3
4
5
6
7
8
val l = b?.length ?: -1
//如果 ?: 左侧表达式非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式。 请注意,当且仅当左侧为空时,才会对右侧表达式求值。

fun foo(node: Node): String? {
val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ……
}

!! 操作符

如果你想要一个 NPE,你可以得到它,但是你必须显式要求它,否则它不会不期而至

##安全的类型转换
如果对象不是目标类型,那么常规类型转换可能会导致 ClassCastException。 另一个选择是使用安全的类型转换,如果尝试转换不成功则返回 null:

1
val aInt: Int? = a as? Int

filterNotNull 过滤非空元素

1
2
3

val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()

异常类,try 表达式,无受检异常

注解、反射(有点绕,先放着用到再看)

typealias 类型别名

不一样的 TODO