Updated on 2017-04-13
https://devdocs.io/kotlin-reference/
https://kotlinlang.org/docs/reference/idioms.html
https://kotlinlang.org/docs/reference/basic-syntax.html
https://kotlinlang.org/api/latest/jvm/stdlib/index.html
https://kotlinlang.org/docs/kotlin-docs.pdf
https://github.com/JetBrains/kotlin/releases/latest
https://jcenter.bintray.com/org/jetbrains/kotlin/kotlin-stdlib/
https://storage.googleapis.com/developers-playground/kp-wrapper-devsite.html
Code
// ABC
/* DEF
GHI */
-------------------------------------------------------
fun main(args: Array<String>) { main 函数(程序入口)
println("Hello World!")
}
-------------------------------------------------------
val a: String 先声明后赋值(只适用于变量,没有赋值时,必须显式声明类型;作为属性时,必须在声明的同时进行赋值)
a = "ABC"
----
val a: String = "ABC" 声明对象的同时进行实例化(显式声明类型)
----
val a = "ABC" 声明对象的同时进行实例化(自动推导类型)
-------------------------------------------------------
Kotlin 中没有(Primitive)基本数据类型,一切皆为(Reference)引用数据类型。
var a = 123 变量(引用可变 get/set)
val b = 123 常量(引用只读 get)
-------------------------------------------------------
val a = """ 原始字符串
fun helloWorld(val name : String) {
println("Hello, world!")
}
"""
----
val a = "ABC"
val b = "$a 的长度为${a.length}" 字符串模板
-------------------------------------------------------
Kotlin 中尽量将变量声明为不可空,不可变。
var a: String = null 编译器报错:不可空变量
var b: String? = null 通过 `?` 明确标识变量可为 null(可空变量)
println(b.length) 编译器报错:不能直接访问可空变量
println(b?.length) 通过 `?.` 访问可空变量,若为 null,则停止继续调用
println(b!!.length) 通过 `!!.` 访问可空变量,若为 null,则抛出 KotlinNullPointerException 异常
try { try-catch
println(b!!.length)
} catch (e: KotlinNullPointerException) {
println("发生空指针异常!")
}
----
val a: String? = null
val b: Int = if (a != null) { 空检查
a.length 不需要通过 `?.` 访问可空变量(Smart Cast)
} else {
-1
}
可简化为
val c: Int = if (a != null) a.length else -1 可用于替代 Java 中的三元运算符
可简化为
val d: Int = a?.length ?: -1 `?:` 操作符:若左边表达式的返回值为 null 则执行右边表达式
-------------------------------------------------------
fun sum(x: Int = 1, y: Int = 1): Unit { 函数(设置参数默认值,以减少重载)
println("$x+$y=${x + y}") 字符串模板
}
可简化为
fun sum(x: Int = 1, y: Int = 1) { 若返回值为 Unit (void),则可省略返回值
println("$x+$y=${x + y}")
}
可简化为
fun sum(x: Int = 1, y: Int = 1) = println("$x+$y=${x + y}") 若函数体只含有 1 句表达式,则可省略函数体和返回值(自动推导类型)
sum()
sum(3)
sum(y = 3) 命名参数
----
输出:
1+1=2
3+1=4
1+3=4
-------------------------------------------------------
fun hello(name: String): String {
return "Hello,$name"
}
可简化为
fun hello(name: String) = "Hello,$name" 若函数体只含有 1 句表达式,可省略函数体和返回值(自动推导类型)
-------------------------------------------------------
fun show(vararg str: String): Unit { vararg:可变长参数,参数数量 [0,∞),视为数组 Array<out T>
for (s in str) { str 为 Array<out String>
print(s + " ")
}
}
show()
----
输出:
无
val array: Array<String> = arrayOf("B", "C")
show("A", *array, "D") (spread)展开操作符:在数组前加上 `*`
----
输出:
A B C D
fun a(x: Int): Boolean {
return x % 2 == 0
}
可简化为
fun a(x: Int) = x % 2 == 0 函数类型:(Int) -> Boolean(需要 Int,返回 Boolean)
@kotlin.internal.InlineOnly
public inline fun println(message: Int) { 函数类型:(Int) -> Unit(需要 Int,返回 Unit)(类库自带函数)
System.out.println(message)
}
val array = arrayOf(1, 2, 3, 4)
array 使用 Lambda 表达式
.filter { it % 2 == 0 }
.forEach { System.out.println(it) }
等同于
array 使用函数引用
.filter(::a)
.forEach(::println)
等同于
val aa: (Int) -> Boolean = ::a 将函数引用存储在变量中,类型(声明)为 "函数类型"
val bb: (Int) -> Unit = ::println
array
.filter(aa)
.forEach(bb)
----
输出:
2
4
-------------------------------------------------------
高阶函数:一种将函数作为参数或者返回值的函数。
↳ 函数参数:
↳ Lambda 表达式:跟 Java8 中的概念相同,只能作为高阶函数的参数或返回值。
↳ 匿名函数:没名字的函数,只能作为高阶函数的参数或返回值。
↳ 命名函数:可以通过函数引用作为高阶函数的参数。
↳ 函数引用:通过在函数名称前加上 `::` 操作符,把命名函数作为参数传入。
val array: Array<Char> = arrayOf('A', 'B', 'C', 'D')
val list: MutableList<Int> = array.mapTo(mutableListOf(), { c -> c.toInt() }) mapTo 为高阶函数,{} 为 Lambda 表达式
可简化为
val list: MutableList<Int> = array.mapTo(mutableListOf()) { c -> c.toInt() } 高阶函数中若最后一个参数是函数参数,可移至括号外;若只需要一个函数参数,可省略括号
可简化为
val list: MutableList<Int> = array.mapTo(mutableListOf()) { it.toInt() } Lambda 表达式中若只接收一个参数,可用 `it` 替代
可简化为
val list: MutableList<Int> = array.mapTo(mutableListOf(), Char::toInt) Lambda 表达式转为函数引用
println(list)
----
输出:
[65, 66, 67, 68]
-------------------------------------------------------
(1..5).reduce { _, _ -> 0 } 0(若不需要 Lambda 表达式中提供的参数,可用 `_` 占位)
-------------------------------------------------------
fun a(i: Int): Int {
return i * 2
}
可简化为
fun a(i: Int) = i * 2 命名函数(有名字的函数)
val list = listOf(1, 2, 3, 4, 5)
list.map(fun(i: Int): Int {
return i * 2
})
可简化为
list.map(fun(i: Int) = i * 2) 匿名函数(没名字的函数)
----
list.map(::a) 对命名函数使用函数引用
----
list.map { it * 2 } Lambda 表达式
-------------------------------------------------------
val list = listOf(1, 2, 3, 4, 5)
list.map({ i -> i * 2 }) 此高阶函数只需要一个函数参数
可简化为
list.map() { i -> i * 2 } 移至括号外
可简化为
list.map { i -> i * 2 } 省略括号
可简化为
list.map { it * 2 } 使用 `it` 替代
-------------------------------------------------------
无标签限制的 this 指向包含当前代码的最内层。
val stringBuilder = StringBuilder("123").apply a@ { 在 Lambda 表达式处显式声明标签,以区分重名标签和 this 对象
println(this@a)
"456".apply {
println(this@apply)
this@a.append(this@apply)
}
}
println(stringBuilder)
----
输出:
123
456
123456
-------------------------------------------------------
有标签限制的 break 跳转至该标签指定的循环,继续后面的表达式。
有标签限制的 continue 跳转至该标签指定的循环,继续下一次迭代。
a@ for (x in 0..9) {
b@ for (y in 10..19) {
if (x == 5 && y == 15) {
break@a 跳转至最外层循环并结束,最后输出:5 14
}
println("$x $y")
}
}
-------------------------------------------------------
无标签限制的 return 返回结果至最直接包含它的函数;
带标签限制的 return 一般应用于高阶函数中的 Lambda 表达式。
Lambda 表达式会形成一个闭包(捕捉使用到的外部变量,形成一个作用域),可以通过 Inline,消除这种开销。
对象是带方法的数据;
闭包是带数据的方法。(Closure)
inline 签名一般与高阶函数搭配使用,以优化 Lambda 表达式,直接将代码写至调用处,来减少函数调用栈的层数,但
会增加代码生成量。
Kotlin 类库中的大部分高阶扩展函数都带有 inline 签名,使其成为内联高阶扩展函数,导致 Lambda 表达式不会引入
新作用域,函数体中的变量和外部环境中的变量具有相同的语义。
fun main(args: Array<String>) {
a()
println("————————————")
b()
println("————————————")
c()
}
fun a() {
val list1 = listOf(1, 2, 3, 4)
println(list1)
val list2 = list1.filter { Lambda 表达式:无标签限制,返回结果至 fun a()(最直接包含此 Lambda 表达式的函数)
print("+ ")
it % 2 == 0
return
}
println()
println(list2)
}
fun b() {
val list1 = listOf(1, 2, 3, 4)
println(list1)
val list2 = list1.filter { Lambda 表达式:有标签限制,返回结果至 filter
print("+ ")
return@filter it % 2 == 0 隐式标签(与接收该 Lambda 表达式的高阶函数同名)
}
println()
println(list2)
}
fun c() {
val list1 = listOf(1, 2, 3, 4)
println(list1)
val list2 = list1.filter(fun(i: Int): Boolean { 匿名函数:返回结果至 filter
print("+ ")
return i % 2 == 0
})
println()
println(list2)
}
----
输出:
[1, 2, 3, 4]
+
————————————
[1, 2, 3, 4]
+ + + +
[2, 4]
————————————
[1, 2, 3, 4]
+ + + +
[2, 4]
-------------------------------------------------------
fun main(args: Array<String>) {
print(1)
a { 未内联高阶函数:return 有 1 个选项,返回结果至 a
print(2)
return@a 隐式标签(与接收该 Lambda 表达式的高阶函数同名)
}
print(3)
----
输出:
123
print(1)
b { 已内联高阶函数:return 有 2 个选项,返回结果至 b(带标签) 或 main(不带标签)(最直接包含此 Lambda 表达式的函数)
print(2)
return
}
print(3)
----
输出:
12
print(1)
b { 已内联高阶函数
print(2)
return@b 隐式标签(与接收该 Lambda 表达式的高阶函数同名)
}
print(3)
----
输出:
123
}
fun a(block: () -> Unit) { 未内联高阶函数
block()
}
inline fun b(block: () -> Unit) { 已内联高阶函数
block()
}
-------------------------------------------------------
注意 inline 修饰函数,crossinline、noinline 修饰函数参数
inline fun a1(block: () -> Unit) {
block() 作为函数调用
}
inline fun a2(crossinline block: () -> Unit) { 可以通过 crossinline 修饰函数参数,交叉内联此函数参数
thread { block() } 作为函数调用
等同于
thread(block = { block() }) 移至括号内并命名参数
}
inline fun x(block: () -> Unit) {
thread(block = block) 编译器报错:不能将内联函数作为参数传入
}
inline fun b(noinline block: () -> Unit) { 可以通过 noinline 修饰函数参数,取消内联此函数参数,从而可以作为参数传入;但 inline 签名就没起到作用了
thread(block = block) 作为普通参数传入
}
data class A(val id: Int, val name: String) : Closeable { 数据类:自动生成 hashCode、equals、toString、copy 函数
override fun close() {
println("close!")
}
}
val a = A(1, "小明") 实例化对象
val b = a.copy(name = "小张") copy 函数(深度复制)
val (x, y) = a 解构声明(component 函数)
println("$x $y") 字符串模板
println(a)
println(b)
----
输出:
1 小明
A(id=1, name=小明)
A(id=1, name=小张)
-------------------------------------------------------
with(a) { 高阶函数
println("[${this.id}, ${this.name}]")
}
----
输出:
[1, 小明]
-------------------------------------------------------
a.use { 由于主动继承自 Closeable,所以能够使用 use 高阶函数(Closeable 接口的扩展函数,用于替代 Java7 的 ARM)
println("[${it.id}, ${it.name}]")
}
----
输出:
[1, 小明]
close!
val list = listOf("A", "B", "C") 生成不可变 List(元素不可被添加或删除,只读)
val set = setOf("A", "B", "C") 生成不可变 Set
val map = mapOf("A" to 0, "B" to 1, "C" to 2) 生成不可变 Map(Kotlin 中的 Map 存储的是 Pair)
val mutableList = mutableListOf("A", "B", "C") 生成可变 List
println(list[0])
println(set.contains("A"))
println(map["A"])
----
输出:
A
true
0
for ((k, v) in map) { 解构声明(Kotlin 中的 Map 存储的是 Pair)
println("$k -> $v")
}
----
输出:
A -> 0
B -> 1
C -> 2
-------------------------------------------------------
val list = listOf('A', 'B', 'C')
list.asIterable() Iterable:急性求值(Eager)(多用于小型集合)(默认)
.filter {
println("filter:$it")
true
}
.map {
println("map:$it")
it.toInt()
}
.first().let(::println)
----
输出:
filter:A
filter:B
filter:C
map:A
map:B
map:C
65
list.asSequence() Sequence:惰性求值(Lazy)(多用于大型集合)(类似于 Java8 中的数据流)
.filter {
println("filter:$it")
true
}
.map {
println("map:$it")
it.toInt()
}
.first().let(::println)
----
输出:
filter:A
map:A
65
-------------------------------------------------------
val map: Map<String, List<Int>> = (1..9)
.map { it * 3 } 映射
.filter { it < 20 } 过滤
.groupBy { it % 2 == 0 } 分组
.mapKeys { 映射
if (it.key) {
"偶数"
} else {
"奇数"
}
}
println(map)
----
输出:
{奇数=[3, 9, 15], 偶数=[6, 12, 18]}
-------------------------------------------------------
val list1 = listOf(1..3, 4..6) [1..3, 4..6]
val list2 = list1.flatMap { it } [1, 2, 3, 4, 5, 6] 平铺
val list3 = list2.map { it * 2 } [2, 4, 6, 8, 10, 12] 映射
-------------------------------------------------------
val intRange = 1..4
val i = intRange.reduce { acc, i -> acc + i } 10(不带初始值)
val j = intRange.fold(-5) { acc, i -> acc + i } 5(带有初始值)
-------------------------------------------------------
val intRange = 1..10
val list = intRange.takeWhile { it % 5 != 0 } [1, 2, 3, 4](一直获取,直到元素不符合条件为止)
-------------------------------------------------------
val list: List<Any> = listOf("A", "B", "C", 1, 2, 3, 4)
list.filter { it is Int && it % 2 != 0 }.forEach(::println)
↳ 判断类型 ↳ 自动转型(Smart Cast) ↳ 函数引用
----
输出:
1
3
for:
val intRange: IntRange = 1..5 范围表达式
for (i in intRange) {
print("$i ")
}
可简化为
for (i in 1..5) { 1 2 3 4 5 (全包含)
print("$i ")
}
for (i in 1 until 5) { 1 2 3 4 (半包含)
print("$i ")
}
for (i in 2..10 step 2) { 2 4 6 8 10 (步长)
print("$i ")
}
for (i in 10 downTo 5) { 10 9 8 7 6 5 (降序)
print("$i ")
}
for (c in "Hello") {
println(c)
}
if (i in 1..10) {
println("YES")
} else {
println("NO")
}
遍历对象并带有索引位置
----
val strs = arrayOf("A", "B", "C")
for ((index, s) in strs.withIndex()) { 对 IndexedValue<T> 的解构声明
println("$index -> $s")
}
strs.forEachIndexed { index, s ->
println("$index -> $s")
}
----
输出:
0 -> A
1 -> B
2 -> C
0 -> A
1 -> B
2 -> C
-------------------------------------------------------
while、do...while:
var i = 0
while (i < 5) {
println(i)
i++
}
do {
println(i)
i++
} while (i < 10)
----
输出:
0
1
2
3
4
5
6
7
8
9
-------------------------------------------------------
when(和所有分支条件进行顺序比较,用于替代 Java 中的 switch):
val i = 8
when (i) { 提供参数,匹配对应参数类型,替代 switch
0, 21 -> println("0 or 21")
in 1..20 -> println("1 to 20") 在
!in 22..100 -> print("x<0 or x>100") 不在
is Int -> print("is Int") 是(Smart Cast)
!is Int -> print("not Int") 不是
else -> println("other")
}
when { 不提供参数,匹配布尔类型,可替代 if-else if 链
i < 5 -> println("first block")
i < 10 -> println("second block")
else -> println("else block")
}
-------------------------------------------------------
流程控制语句可作为表达式提供返回值。
val s = if (Math.random() - Math.random() > 0) {
"成功"
} else {
"失败"
}
可简化为
val s = if (Math.random() - Math.random() > 0) "成功" else "失败" 替代三元运算符
val s2 = when (Math.random() - Math.random() > 0) {
true -> "成功"
false -> "失败"
else -> "失败"
}
-------------------------------------------------------
fun smartCast(x: Any): Boolean { 自动类型转换(智能转型)
if (x is Boolean) { 通过类型检查后自动转换类型
return x
} else if (x is Int) {
return x > 0
} else if (x is String) {
return x.startsWith("Hello")
} else {
return false
}
}
可简化为
fun smartCast(x: Any): Boolean { 用 when 替代 if-else if 链
when (x) {
is Boolean -> return x
is Int -> return x > 0
is String -> return x.startsWith("Hello")
else -> return false
}
}
可简化为
fun smartCast(x: Any): Boolean { 用 when 作为返回值
return when (x) {
is Boolean -> x
is Int -> x > 0
is String -> x.startsWith("Hello")
else -> false
}
}
可简化为
fun smartCast(x: Any) = when (x) { 简化表达式(省略函数体和返回值)
is Boolean -> x
is Int -> x > 0
is String -> x.startsWith("Hello")
else -> false
}
val any: Any = "ABC" as Any 强制类型转换(若转换失败,则抛出异常 java.lang.ClassCastException)
----
if (any is String) { 等同于 instanceof,若通过检查,则在代码块中进行智能转型(Smart Cast)
println(any.length) 类型:String
}
println(any.length) 类型:Any,无 length 属性,报错
-------------------------------------------------------
fun String.abc(c: Char): String { 扩展函数(给一个类添加新的功能)
return this.filter { it != c } false 过滤,true 不过滤
}
可简化为
fun String.abc(c: Char) = this.filter { it != c }
println("Hello".abc('l'))
----
输出:
Heo
fun String.Companion.abc() { 静态扩展函数(给一个类的伴生对象添加新的功能)
println("ABC")
}
可简化为
fun String.Companion.abc() = println("ABC")
String.abc() 直接调用而不通过对象
----
输出:
ABC
val String.str1: String 扩展属性(只能为 val),同样也有静态扩展属性
get() = "Hello"
println("".str1)
----
输出:
Hello
-------------------------------------------------------
中缀函数条件:
1. 为成员函数或扩展函数
2. 函数签名带有 infix 关键字
3. 只接收 1 个参数
infix fun Int.abc(x: Int): Int {
println("OK!")
return this + x
}
println(1.abc(2).abc(3)) 点号标记法
等同于
println(1 abc 2 abc 3) 中缀标记法
----
输出:
OK!
OK!
6
-------------------------------------------------------
var <propertyName>: <PropertyType> [= <property_initializer>]
[<getter>]
[<setter>]
Kotlin 中对属性的访问自动转为编译器自动生成的默认 get/set,我们可对其进行自定义。
----
class A {
var s: String = "Hi"
get() { get 可见性与此属性可见性一致
println("Get")
return field
}
set(value) { set 可见性可设置为 private;另外 val 没有 set 函数和后备 field
if (value.startsWith("H")) {
println("Set true")
field = value field:当前属性 s;this:当前类 A
} else {
println("Set false")
}
}
}
val a = A()
a.s = "World"
println(a.s)
a.s = "Hello"
println(a.s)
----
输出:
Set false
Get
Hi
Set true
Get
Hello
-------------------------------------------------------
委托属性(get/set 的工厂函数)
class A {
val s1: String by lazy { 延迟属性:只会在第一次访问 get 的时候执行该代码块,并赋值(延迟加载)
println("123") ↳ 计算时默认为线程同步 (synchronized),若不需要可关闭:by lazy(LazyThreadSafetyMode.NONE) {}
"AAA"
}
var s2: String by Delegates.observable("XXX") { prop, old, new -> 可观察属性:属性改变之后回调,afterChange
println("$old -> $new") ↳ 初始值
}
var s3: String by Delegates.vetoable("XXX") { prop, old, new -> 可观察属性:属性改变之前回调,beforeChange
println("$old -> $new") ↳ 初始值
return@vetoable true true 接受,false 丢弃
}
}
val a = A()
println(a.s1)
a.s2 = "BBB"
println(a.s2)
a.s3 = "CCC"
println(a.s3)
----
输出:
123
AAA
XXX -> BBB
BBB
XXX -> CCC
CCC
委托属性:所有属性存储至 Map 中
----
class User(val map: Map<String, Any?>) { 若属性包含 var 则需换成 MutableMap
val name: String by map 属性名作为 Key
val age: Int by map
}
val user = User(mapOf("name" to "ABC", "age" to 25)) Key-Value(Kotlin 中的 Map 存储的是 Pair)
println("${user.name} ${user.age}")
----
输出:
ABC 25
-------------------------------------------------------
属性延迟加载(延迟初始化)
----
class A {
val a: String by lazy { val 使用委托属性 by lazy {}:只会在第一次访问 get 的时候执行该代码块,并赋值
println("123")
"AAA"
}
lateinit var b: String var 使用关键字 lateinit:可稍后手动初始化(若访问 get 时未初始化,则抛出 UninitializedPropertyAccessException 异常)
}
val a = A()
println(a.a)
a.b = "BBB"
println(a.b)
----
输出:
123
AAA
BBB
-------------------------------------------------------
编译期常数值:属性值在编译期间就能够确定,需满足以下条件:
1. 为顶级属性或者是 object 的成员
2. 为 String 或者是基本类型
3. 为 val 且没有自定义的 get 函数
const val i = 5
class A {
var name = ""
var age = 20
}
可简化为
class A constructor(var name: String = "", var age: Int = 20) { 主构造函数
}
可简化为
class A(var name: String = "", var age: Int = 20) 主构造函数无注解和修饰符,可省略 constructor;无类体,可省略 {}
-------------------------------------------------------
data class A(var name: String, var age: Int) { Kotlin 中的类可以有一个主(要)构造函数和多个次(要)构造函数
init {
println("主构造函数 or 初始化块")
}
constructor(name: String) : this(name, 0) { 声明次构造函数
println("次构造函数1")
}
constructor(age: Int) : this("无名氏", age) {
println("次构造函数2")
}
}
println(A("张三", 20))
println(A("张三"))
println(A(20))
//println(A()) 报错,没有无参构造函数
----
输出:
主构造函数 or 初始化块
A(name=张三, age=20)
-
主构造函数 or 初始化块
次构造函数1
A(name=张三, age=0)
-
主构造函数 or 初始化块
次构造函数2
A(name=无名氏, age=20)
-------------------------------------------------------
如果主构造函数的所有参数都有默认值,则默认会生成一个无参次构造函数。
如果没有声明任何(主或次)构造函数,则默认会生成一个无参主构造函数。
data class A private constructor(var name: String, var des: String) { 指定主构造函数为 private
constructor(name: String) : this(name, "欢迎:$name") 默认 public
}
println(A("张三"))
//println(A("张三", "ABC")) 报错,主构造函数为 private
----
输出:
A(name=张三, des=欢迎:张三)
-------------------------------------------------------
import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.BorderPane
import javafx.stage.Stage
fun main(args: Array<String>) { JavaFX
Application.launch(A::class.java, *args) 从 KClass 对象获得 Class 对象
}
class A : Application() { 继承 Application 抽象类(显式调用构造函数)
override fun start(primaryStage: Stage) { 实现抽象函数
primaryStage.title = "ABC"
primaryStage.width = 400.toDouble()
primaryStage.height = 300.toDouble()
primaryStage.scene = Scene(BorderPane())
primaryStage.show()
}
}
interface A { 接口(跟 Java 一样,单继承多实现)
val i: Int 抽象属性
val j: Int 属性:已提供访问器实现(若属性修饰为 var,还需提供 set() 实现)
get() = 2
fun a() 抽象函数
fun b() {} 函数:已提供函数实现
}
class B : A { 通过类实现接口
override val i: Int
get() = 1
override fun a() {}
}
val a = object : A { 通过对象表达式实现接口(匿名内部类)
override val i: Int
get() = 1
override fun a() {}
}
-------------------------------------------------------
对象表达式(匿名内部类):
val o = object {
val x = 1
val y = 2
val z = 3
operator fun component1() = x 解构函数
operator fun component2() = y 解构函数
operator fun component3() = z 解构函数
}
等同于
val o = object : Any() { Kotlin 中 Any 是所有类的父类
val x = 1
val y = 2
val z = 3
operator fun component1() = x
operator fun component2() = y
operator fun component3() = z
}
val (x, y, z) = o 解构声明
println(x + y + z) 6
println(o.x + o.y + o.z) 6
-------------------------------------------------------
对象声明(单例模式):
object MyObject { 单例对象(Singleton)
val AUTHOR = "XhstormR" 属性为 static
fun hello(): String { 函数不为 static,可加上 "@JvmStatic" 注解成为 static 函数,针对属性同样还有 "@JvmField",都仅对 Java 互操作有影响。
return "Hello $AUTHOR!"
}
}
println(MyObject.AUTHOR)
println(MyObject.hello())
----
输出:
XhstormR
Hello XhstormR!
-------------------------------------------------------
open class A A 类
interface B B 接口
class C : A(), B C 继承 A 并实现 B(类默认生成无参主构造函数,接口无构造函数且默认开放)
(operator)操作符重载
----
class A(var i: Int) {
operator fun inc(): A { a++
i++
return this
}
operator fun dec(): A { a--
i--
return this
}
operator fun invoke(): Int { a()
return i
}
operator fun get(index: Int): Int { a[0]
return i
}
operator fun set(index: Int, int: Int) { a[0] = 123
i = int
}
operator fun compareTo(o: A): Int { >,<,>=,<=
return i.compareTo(o.i)
}
override operator fun equals(other: Any?): Boolean { ==,!=(IDE 生成)
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as A
if (i != other.i) return false
return true
}
override fun hashCode(): Int { IDE 生成
return i
}
override fun toString(): String { IDE 生成
return "A(i=$i)"
}
}
Java:
class Test1 {
static {
System.out.println("1父类静态初始化块");
}
{
System.out.println("2父类初始化块");
}
Test1() {
System.out.println("3父类构造方法");
}
}
----
class Test2 extends Test1 {
static {
System.out.println("1子类静态初始化块");
}
{
System.out.println("2子类初始化块");
}
Test2() {
System.out.println("3子类构造方法");
}
}
----
class Initial {
public static void main(String[] args) {
Test1 a = new Test2();
}
}
----
输出:
1父类静态初始化块
1子类静态初始化块
2父类初始化块
3父类构造方法
2子类初始化块
3子类构造方法
-------------------------------------------------------
Kotlin:
open class Test1 { Kotlin 跟 Java 相反,类和方法都默认为 final(最终),需用 open(开放)指明可以继承
companion object { 伴生对象(静态内部类 Companion)(static 初始化块、方法、属性)
init {
println("1父类静态初始化块")
}
}
init {
println("2父类初始化块")
println("3父类构造函数(主)")
}
}
----
class Test2 : Test1() { 需显式调用父类的构造方法
companion object { 伴生对象(静态内部类 Companion)(static 初始化块、方法、属性)
init {
println("1子类静态初始化块")
}
}
init {
println("2子类初始化块")
println("3子类构造函数(主)")
}
}
----
fun main(args: Array<String>) {
val a: Test1 = Test2() 多态
val companion = Test2.Companion 获得类中的伴生对象
}
----
输出:
1父类静态初始化块
1子类静态初始化块
2父类初始化块
3父类构造函数(主)
2子类初始化块
3子类构造函数(主)
-------------------------------------------------------
class A {
companion object { 伴生对象(静态内部类 Companion)(static 初始化块、方法、属性)
var i = 0
init {
println("静态初始化块")
}
}
init {
println("${++i} 初始化块 构造函数(主)")
}
}
A()
A()
A()
A()
----
输出:
静态初始化块
1 初始化块 构造函数(主)
2 初始化块 构造函数(主)
3 初始化块 构造函数(主)
4 初始化块 构造函数(主)
-------------------------------------------------------
class A {
companion object { 伴生对象(静态内部类 Companion)(static 初始化块、方法、属性)
val list = arrayListOf<A>()
}
init {
list.add(this)
}
}
A()
A()
A()
println(A.list)
----
输出:
[A@2f0e140b, A@7440e464, A@49476842]
-------------------------------------------------------
默认内部类静态化,可在一定程度上降低发生内存泄露的概率。
很多时候内部类仅用来存储数据,并不需要访问外部类的成员。
class Outer {
private val bar = 1
class Nested { Java 中的静态内部类:相当于独立出来的类,不会持有其外部类的强引用。
fun foo() = 2
}
}
Outer.Nested().foo() 不需要实例化外部类
----
class Outer {
private val bar = 1
inner class Nested { Java 中的内部类:默认持有其外部类的强引用。
fun foo() = bar 可以访问外部类的成员
}
}
Outer().Nested().foo() 需要实例化外部类
val array = arrayOfNulls<Int>(5) 创建容量为 5 以 null 填充的空数组
for (i in array.indices) {
println(array[i])
}
----
输出:
null
null
null
null
null
-------------------------------------------------------
val s1 = "ABC"
val s2 = StringBuilder("ABC").toString()
println(s1 == s2) 比较实际内容(operator 重载,调用 equals()),对应 !=
println(s1 === s2) 比较内存地址(Java 中的 `==`),对应 !==
----
输出:
true
false
-------------------------------------------------------
Kotlin:
val a: Char = 'A' 在 Java 中为基本数据类型 char
val b: Char? = 'B' 在 Java 中为引用数据类型 Character
println(a)
println(b)
Convert to Java:
char a = 65;
Character b = Character.valueOf('B');
System.out.println(a);
System.out.println(b);
----
Kotlin:
val arrayOf = arrayOf(1, 2, 3)
val intArrayOf = intArrayOf(4, 5, 6) 避免装箱,提高性能
Convert to Java:
Object[] elements$iv = new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)};
Integer[] arrayOf = (Integer[])((Object[])elements$iv);
int[] var10000 = new int[]{4, 5, 6};
-------------------------------------------------------
FileOutputStream("""D:\123.txt""", true).bufferedWriter().use { it.write("${LocalDateTime.now()}\n") } 写
FileInputStream("""D:\123.txt""").bufferedReader().useLines { it.forEach(::println) } 读
-------------------------------------------------------
println(String().javaClass) 从实例对象获得 Class 对象
println(String::class.java) 从 KClass 对象获得 Class 对象
----
输出:
class java.lang.String 完全类名限定符
class java.lang.String
Script
D:\Download\kotlinc\bin>kotlinc -script DeleteFile.kts
JavaScript
D:\Download\kotlinc\bin>kotlinc-js -output 123.js A.kt
D:\Download\kotlinc\lib\kotlin-stdlib-js.jar\kotlin.js
@JsName("main")
fun main(args: Array<String>) {
js("""document.write(message+"<br/>")""")
alert(message)
}
val message = "Hello JavaScript."
external fun alert(message: Any?)//暴露外部 API
<html>
<head>
<meta charset="UTF-8">
<title>123</title>
</head>
<body>
<script type="text/javascript" src="kotlin.js"></script>
<script type="text/javascript" src="123.js"></script>
</body>
</html>