1 kotlin概述
-
Kotlin 是一种目标平台为 JVM,由 JetBrains 开发的,开源静态类型语言,具有concise(代码简洁)safe(安全)versatile(多平台支持)interoperable(完全兼容java)的特点。
-
Kotlin 是一种面向对象语言。不过它支持高阶函数以及 lambda 表达式和顶层函数。
-
Kotlin 生成的字节码兼容 Java 6 以及更新版本。
-
kotlin避免了java语言的一些弊端,显然kotlin借鉴过java,另外据kotlin作者,kotlin还借鉴了C#,比如扩展。
-
扩展和函数绝对是kotlin的killing feature。
2 基本类型/变量/流程控制/返回
- 基本类型与java类似,有:数值,字符,布尔,以及数组。
Char 类表示字符类型,在 Kotlin 中Char不是数值类型。
Array 类表示数组。
- 变量是值,值有可变与不可变之分:
Kotlin 中使用 var 和 val 来界定 reference 的可变性,尽量保持 reference 是 immutable 的。kotlin会根据变量的赋值自动推断其具体类型。不可变常量如果没有初始化值,则必须声明其具体类型。
- 变量是值,值还有空与不空之分:
可空变量, Int? ,绕过java的NPE
- 变量是引用,引用有值类型/引用类型之分:
kotlin中可以给Double类扩展,可以用整型可空Int? ,试想,如果是值类型哪有null的概念。所以Kotlin 中没有原始类型,从语法上看,kotlin中变量类型皆是reference。但其实 Int 类型编译成字节码后是 int 类型(value type)。另见Kotlin 一年の使用报告 - 类型设计
- 智能类型转换
if ( obj is string ){
//这时obj 自动转换为 String 类型
return obj.length }
- 变量的赋值时机,声明时赋值/被访问时赋值(延迟赋值):
lateinit 修饰的变量不能二次赋值;
lateinit 不能修饰 Int、Long 等基本类型,因为它们字节码里是值类型,本身会赋予默认值,所以一修饰就是二次赋值;
- kotlin里流程控制语句每个分支块都是表达式,表达式是有返回值的。
//if表达式,
val max = if (a > b) a else b
//when表达式
fun cases(obj: Any) {
when (obj) {
1 -> print("one")
"hello" -> print("Greeting")
is Long -> print("Long")
!is Long -> print("Not a string")
else -> print("Unknown")
}
}
- for 可以对任何具有迭代器的类型的对象进行循环:
有iterator()方法返回迭代类型;
有hasNext()方法返回Boolean;
有next();
for (item in collection) //集合有迭代器嘛
print(item)
- 通过 list 或者 array 的索引进行迭代:
for (i in array.indices)
print(array[i])
- 范围表达式Range
if (x !in 0..array.lastIndex) print("Out")
- 函数命名后自动具备标签:
foo outer() {
foo inner() {
return@outer
}
}
2 类/对象/函数
1 类的声明:默认final; open修饰的类表示可继承;sealed修饰的类表示密封类;data修饰的类表示数据类
-
sealed修饰的密封类:作用类似枚举类。密封类的所有子类必须嵌套在密封类的内部。
-
data修饰的数据类:我们经常create a class to do nothing but hold data.数据类会自动根据主构造器生成equals()/hashCode()/toString()/componentN()/copy()。标准类 Pair
-
inner修饰的内部类:内部类持有一个外部类对象。
-
enum修饰的枚举类
2 类可以包含:构造器,init初始化代码块,属性,函数,内部类,对象声明。
- 构造器
只要主构造函数的所有属性参数都有默认值,编译器就会生成一个无参的构造函数。
- 属性
属性是变量,变量的特性都适用于它。
属性的getter/setter在kotlin中默认 public。
field 关键词只能用于属性的访问器,就是在setter方法中代表本属性。
lateinit,属性延迟初始化,第一次被访问时才赋值。
Delegated properties委托属性,属性的get set委托给另一个对象,by语句。
委托类提供getter/setter的函数用operator标示。委托类,是一种继承。
属性观察器,var name: String by Delegates.observable
lazy和lateinit特性可以视作基于Delegated properties的一种实现,类似Objective-C中的KVO。
3 函数/函数式思想
-
函数式语言:函数是头等公民;函数是一种引用类型,叫function type;只有表达式(if else、when 等当作多元运算符);
-
默认值参数,可以减少重载。可变参数,vararg修饰
-
局部函数,一个函数在另一个函数内
-
lambda表达式,参数箭头函数体,作为参数传入一个函数。(感觉lambda 表达式是对函数的一种抽象啊,或者说是对匿名函数的一种简化)
-
高阶函数,参数或返回值是函数或lambda的函数。 Collection 的高阶函数集,如map、filter (对比java8的Stream)
-
闭包,这个是作用域问题,局部函数访问外部函数的局部变量,形成闭包。
闭包的典型原则是这样:一个输入(参数),一个输出。
所以表象是,内部函数访问外部函数的局部变量。其实是,把一个函数的多个参数转换成一个参数。
因为抽象的时候,多参和单参要统一抽象,那就多参变单参,再加上那个原则,你自然就写成闭包的方式。www.zhihu.com/question/51…
- 内联函数,它的函数体作为外部函数的函数体的一部分。
高阶函数会形成闭包,那变量调用就会跨越堆内存和函数栈内存(想想java里匿名内部类访问方法局部变量为啥要final),通过内联化inline,可以消除这种开销。 但是,这个时候内联函数的return,直接就把外部函数return了,这叫non-local返回,crossinline修饰可以禁止这种返回。
- 函数返回什么,不就是说,这个函数是返回类型的一个实例。
4 对象
val customer = Customer("Joe Smith") 没有 new 关键字
对象表达式,相当于匿名内部类,就是对某类做了轻微改变的一个对象。
对象声明,在对象表达式前面有object关键字。这样就闷声地在kotlin里搞了个单例模式。一颗赛艇
对象声明会延迟初始化,对象表达式不会。
伴生对象,一个类里的对象声明且有companion关键字,直接拿类名调用,用起来像java里的静态成员(kotlin没有静态),但其实运行时还是一个实例成员。
解构声明,把一个对象解构成很多变量
5 继承
Kotin 中所有的类都有共同的父类 Any
如果子类没有主构造函数,则必须在每一个构造函数中用 super 关键字初始化基类。
kotlin 中的类默认是 final,接口/抽象类默认是open。open的类可被继承,open的函数可被重写。open class Base(p: Int)
6 扩展/运算符重载
- Kotlin 支持函数扩展和属性扩展。
fun Int.double() {
return this * 2
}
2.double() == 4
- operator overloading 运算符重载
用operator关键字修饰扩展函数
class Map<Key, Value> {
operator get(key: Key): Value {
// get and return the value from the map here
}
}
7 范型
声明处型变:out修饰的只返回不消费,in修饰的只消费而不返回。
reified修饰范型,那在函数内部就可以像一个类一样使用这个范型类型。
3 集合/构建器
可变集合和不可变集合,sort、zip、fold、reduce
构建器(builders)的概念在Groovy社区非常热门。 使用构建器我们可以用半声明(semi-declarative)的方式定义数据。类似的构建器kotlin也可以,格式像DSL,实际上是一个函数,其参数是一个lambda 表达式 。
动态类型,kotlin是静态类型语言,dynamic类型关闭了Kotlin的类型检查,可以在dynamic变量上调用任何属性或任何函数。这样就可以支持与JavaScript的相互调用。
附
kotlinlang.org/docs/refere…
try.kotlinlang.org/
github.com/antoniolg/B…
github.com/YoungPeanut…