-
基础类型
Double Float Long Int Short Byte,类型间的转换都有提供方法如.toInt()
等。 -
Class类
Kotlin中所有的类都是final,如果允许别的类继承这个类,需要添加open
注解。
主构造函数不能包含任意代码。初始化代码可以放在init
做前缀的初始化块内
class Customer(name: String) {
init {
logger,info("Customer initialized with value ${name}")
}
}
- 密封类
密封类用于代表严格的类结构,值只能是有限集合中的某种类型。这就相当于一个枚举类的扩展:枚举值集合的类型是严格限制的,但是每个枚举常量只有一个实例,而密封类的子类可以有包含不同状态的多个实例。
实例如下:
/**
* 心跳包.. Result
*/
sealed class HeartBeatReqResult{
class Error(val error:Exception):HeartBeatReqResult()
class Ack(val ack:AutoId):HeartBeatReqResult()
}
密封类的子类的扩展可以在任何地方,不必在密封类声明内部进行。
- 类的属性与字段
完整属性声明语法:
var <propertyName>: <PropertyType> [ = <property_initializer> ]
<getter>
<setter>
-
延迟初始化
lateinit
lateinit
只能用在类的var
类型的可变属性中,不能用在构造方法中,并且属性不能有getter和setter访问器。这个属性的类型必须是非空的,同样也不能是基本类型。 -
可见行修饰
internal
同一模块内可见。 -
函数扩展
fun <T> MutableList<T>.swap(x: Int, y: Int) {
val tmp = this[x] // 'this' corresponds to the list
this[x] = this[y]
this[y] = tmp
}
- 扩展是被静态解析的
扩展实际上并没有修改它所扩展的类。定义一个扩展,你并没有插入一个新的成员,只是能够让类的实例对象能够通过.
调用新的函数。
- 如果有同名同参数的成员函数和扩展函数,调用的时候必然会使用成员函数。
class C {
fun foo() { println("member") }
}
fun C.foo() { println("extension") }
调用``c.foo()``的时候,他会输出"member",而不是"extension"
- 扩展函数是静态分发的,扩展函数的调用是由发起函数调用的表达式决定的,而不是在运行时动态获取的表达式决定的。
open class C
class D: C()
fun C.foo() = 'c'
fun D.foo() = 'd'
调用``c.foo()``的时候,输出"c",
调用``d.foo()``的时候,输出"d".
- 数据类data class
编译器会自动根据主构造函数中声明的所有属性添加equal()/hashCode/toString()/copy()函数
copy属性
val jack = User(name = "jack", age = 1)
val olderJack = jack.copy(age = 2)
标准数据类提供了Pair
和Triple
。
- 内部类
类可以嵌套在其他类中,类可以标记为inner
这样就可以访问外部类的成员。内部类拥有外部类的一个对象引用:
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}
val demo = Outer().Inner().foo() //==1
11.匿名内部类
匿名内部类的实例是通过对象表达式创建的:
window.addMouseListener(object: MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// ...
}
override fun mouseEntered(e: MouseEvent) {
// ...
}
})
- 对象表达式
有时候我们只需要一个没有父类的对象,可以这样写
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
13.对象声明
- 单例声明
object Singleton
- 伴随对象
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create()
14.代理属性
val/var <property name>: <Type> by <expression>
- 代理延迟
lazy()
是一个接受 lamdba 并返回一个实现延迟属性的代理:第一次调用get()
执行 lamdba 并传递lazy()
并存储结果,以后每次调用get()
时只是简单返回之前存储的值。
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
//// 输出
computed!
Hello
Hello
- 可观察属性
Delegates.observable()
需要两个参数:一个初始值和一个用于修改的 handler 。每次我们给属性赋值时都会调用handler (在初始赋值操作后)。它有三个参数:一个将被赋值的属性,旧值,新值:
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "first"
user.name = "second"
}
//// 输出
\ -> first
first -> second
- 在Map中存储属性
把属性值存储在 map 中是一种常见的使用方式,这种操作经常出现在解析 JSON 或者其它动态的操作中。这种情况下你可以使用 map 来代理它的属性。
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
class MutableUser(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
- 尾递归函数
Kotlin 支持函数式编程的尾递归。这个允许一些算法可以通过循环而不是递归解决问题,从而避免了栈溢出。当函数被标记为 tailrec 时,编译器会优化递归,并用高效迅速的循环代替它。
使用 tailrec 修饰符必须在最后一个操作中调用自己。在递归调用代码后面是不允许有其它代码的,并且也不可以在 try/catch/finall 块中进行使用。当前的尾递归只在 JVM 的后端中可以用
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
等价于
private fun findFixPoint(): Double {
var x = 1.0
while (true) {
val y = Math.cos(x)
if ( x == y ) return y
x = y
}
}
16.协程
一般来说,协程是一种可以不阻塞线程但却可以被挂起的计算过程。线程阻塞总是昂贵的,但协程的挂起基本没有什么开销。
- 挂起函数
suspend
suspend fun doSomething(foo: Foo): Bar{
...
}
- Ranges
.. step
downTo step
in
!in
- 类型检查与转换
is
!is
as
as?
- 空安全
?.
?:
.let{ }
as?
!!
- 函数引用
fun isOdd(x: Int) =x % 2 !=0
val numbers = listOf(1, 2, 3)
println(numbers.filter( ::isOdd) ) //prints [1, 3]
- 属性引用
在 kotlin 中访问顶级类的属性,我们也可以使用 :: 操作符:
var x = 1
fun main(args: Array<String>) {
println(::x.get())
::x.set(2)
println(x)
}
网友评论