依赖
core-ktx
1 | +--- androidx.core:core-ktx:1.7.0 |
kotlin-stdlib
1 | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.20 |
从上述看kotlin-stdlib是关键的kotlin库
基础
解构
1 | fun main(args: Array<String>) { |
密封类
每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。
有限几种类型。使用when时,不需要有else
内联类
1
2
3
4
5
6
7
8inline class Name(val s: String) {
val length: Int
get() = s.length
fun greet() {
println("Hello, $s")
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154public final class Name {
/jvm/JvmInline;()
1, 7, 1}, k=1, xi=48, d1={"\u0000*\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\u0008\u0003\n\u0002\u0010\u0008\n\u0002\u0008\u0005\n\u0002\u0010\u000b\n\u0002\u0008\u0004\n\u0002\u0010\u0002\n\u0002\u0008\u0007\u0008\u0087@\u0018\u00002\u00020\u0001B\u0012\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u00f8\u0001\u0000\u00a2\u0006\u0004\u0008\u0004\u0010\u0005J\u001a\u0010\u000c\u001a\u00020\r2\u0008\u0010\u000e\u001a\u0004\u0018\u00010\u0001H\u00d6\u0003\u00a2\u0006\u0004\u0008\u000f\u0010\u0010J\r\u0010\u0011\u001a\u00020\u0012\u00a2\u0006\u0004\u0008\u0013\u0010\u0014J\u0010\u0010\u0015\u001a\u00020\u0007H\u00d6\u0001\u00a2\u0006\u0004\u0008\u0016\u0010\u0009J\u0010\u0010\u0017\u001a\u00020\u0003H\u00d6\u0001\u00a2\u0006\u0004\u0008\u0018\u0010\u0005R\u0011\u0010\u0006\u001a\u00020\u00078F\u00a2\u0006\u0006\u001a\u0004\u0008\u0008\u0010\u0009R\u0011\u0010\u0002\u001a\u00020\u0003\u00a2\u0006\u0008\n\u0000\u001a\u0004\u0008\n\u0010\u000b\u0088\u0001\u0002\u00f8\u0001\u0000\u0082\u0002\u0004\n\u0002\u0008\u0019\u00a8\u0006\u0019"}, d2={"LName;", "", "s", "", "constructor-impl", "(Ljava/lang/String;)Ljava/lang/String;", "length", "", "getLength-impl", "(Ljava/lang/String;)I", "getS", "()Ljava/lang/String;", "equals", "", "other", "equals-impl", "(Ljava/lang/String;Ljava/lang/Object;)Z", "greet", "", "greet-impl", "(Ljava/lang/String;)V", "hashCode", "hashCode-impl", "toString", "toString-impl", "kotlin-demo"}) /Metadata;(mv={
// access flags 0x12
private final Ljava/lang/String; s
Bytecode .ast.bytecode.
public final String getS() {
aload 0
getfield 'Name.s','Ljava/lang/String;'
areturn
}
.ast.bytecode.Bytecode
public final static int getLength-impl(String a) {
aload 0
invokevirtual 'java/lang/String.length','()I'
ireturn
}
.ast.bytecode.Bytecode
public final static void greet-impl(String a) {
_new 'java/lang/StringBuilder'
dup
invokespecial 'java/lang/StringBuilder.<init>','()V'
ldc "Hello, "
invokevirtual 'java/lang/StringBuilder.append','(Ljava/lang/String;)Ljava/lang/StringBuilder;'
aload 0
invokevirtual 'java/lang/StringBuilder.append','(Ljava/lang/String;)Ljava/lang/StringBuilder;'
invokevirtual 'java/lang/StringBuilder.toString','()Ljava/lang/String;'
getstatic 'java/lang/System.out','Ljava/io/PrintStream;'
swap
invokevirtual 'java/io/PrintStream.println','(Ljava/lang/Object;)V'
return
}
.ast.bytecode.Bytecode
public static String toString-impl(String a) {
_new 'java/lang/StringBuilder'
dup
invokespecial 'java/lang/StringBuilder.<init>','()V'
ldc "Name(s="
invokevirtual 'java/lang/StringBuilder.append','(Ljava/lang/String;)Ljava/lang/StringBuilder;'
aload 0
invokevirtual 'java/lang/StringBuilder.append','(Ljava/lang/String;)Ljava/lang/StringBuilder;'
bipush 41
invokevirtual 'java/lang/StringBuilder.append','(C)Ljava/lang/StringBuilder;'
invokevirtual 'java/lang/StringBuilder.toString','()Ljava/lang/String;'
areturn
}
Bytecode .ast.bytecode.
public String toString() {
aload 0
getfield 'Name.s','Ljava/lang/String;'
invokestatic 'Name.toString-impl','(Ljava/lang/String;)Ljava/lang/String;'
areturn
}
.ast.bytecode.Bytecode
public static int hashCode-impl(String a) {
aload 0
invokevirtual 'java/lang/String.hashCode','()I'
ireturn
}
Bytecode .ast.bytecode.
public int hashCode() {
aload 0
getfield 'Name.s','Ljava/lang/String;'
invokestatic 'Name.hashCode-impl','(Ljava/lang/String;)I'
ireturn
}
.ast.bytecode.Bytecode
public static boolean equals-impl(String a,Object b) {
aload 1
_instanceof 'Name'
ifne l0
iconst_0
ireturn
l0
aload 1
checkcast 'Name'
invokevirtual 'Name.unbox-impl','()Ljava/lang/String;'
aload 0
swap
invokestatic 'kotlin/jvm/internal/Intrinsics.areEqual','(Ljava/lang/Object;Ljava/lang/Object;)Z'
ifne l1
iconst_0
ireturn
l1
iconst_1
ireturn
}
Bytecode .ast.bytecode.
public boolean equals(Object a) {
aload 0
getfield 'Name.s','Ljava/lang/String;'
aload 1
invokestatic 'Name.equals-impl','(Ljava/lang/String;Ljava/lang/Object;)Z'
ireturn
}
.ast.bytecode.Bytecode
private void <init>(String a) {
aload 0
invokespecial 'java/lang/Object.<init>','()V'
aload 0
aload 1
putfield 'Name.s','Ljava/lang/String;'
return
}
.ast.bytecode.Bytecode
public static String constructor-impl(String a) {
// annotable parameter count: 1 (invisible)
aload 0
ldc "s"
invokestatic 'kotlin/jvm/internal/Intrinsics.checkNotNullParameter','(Ljava/lang/Object;Ljava/lang/String;)V'
aload 0
areturn
}
.ast.bytecode.Bytecode
public final static Name box-impl(String a) {
_new 'Name'
dup
aload 0
invokespecial 'Name.<init>','(Ljava/lang/String;)V'
areturn
}
.ast.bytecode.Bytecode
public final String unbox-impl() {
aload 0
getfield 'Name.s','Ljava/lang/String;'
areturn
}
.ast.bytecode.Bytecode
public final static boolean equals-impl0(String a,String b) {
aload 0
aload 1
invokestatic 'kotlin/jvm/internal/Intrinsics.areEqual','(Ljava/lang/Object;Ljava/lang/Object;)Z'
ireturn
}
}中缀函数
1
2
3
4
5
6
7infix fun Int.shl(x: Int): Int { …… }
// 用中缀表示法调用该函数
1 shl 2
// 等同于这样
1.shl(2)中缀函数调用的优先级低于算术操作符、类型转换以及 rangeTo 操作符。
尾递归函数
作用域函数
let
1
2
3
4
5
6
7fun main() {
val person = Person("songpengfei",32,"beijing").let {
it.age = 21
it // 需要返回it
}
println(person.age) // let闭包中上下文是it
}run
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16fun main() {
val person = Person("songpengfei", 32, "beijing").run {
age = 21
this // 需要返回it
}
println(person.age) // let闭包中上下文是this
}
fun main() {
val person = run {
val person = Person("songpengfei", 32, "beijing")
person.age = 21
person
}
println(person.age)
}apply
1
2
3
4
5
6fun main() {
val person = Person("songpengfei", 32, "beijing").apply {
age = 21
}
println(person.age) // 同run
}also
1
2
3
4
5
6fun main() {
val person = Person("songpengfei", 32, "beijing").also {
it.age = 21
}
println(person.age) // 同let
}with
1
2
3
4
5
6
7fun main() {
val p = with(Person("songpengfei", 32, "beijing")) {
age = 21
this
}
println(p)
}takeIf
1
2
3
4
5
6fun main() {
val person = Person("songpengfei", 32, "beijing").takeIf {
it.age != 32
}
println(person)
}takeUnless
1
2
3
4
5
6fun main() {
val person = Person("songpengfei", 32, "beijing").takeUnless {
it.age == 32
}
println(person)
}解构声明
1
2
3
4
5
6data class Person(var name: String, var age: Int, var city: String)
fun main() {
val (name,age) = Person("song",32,"beijing")
println(name)
println(age)
}
data类 会生成 componentN函数This 表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class A { // 隐式标签 @A
inner class B { // 隐式标签 @B
fun Int.foo() { // 隐式标签 @foo
val a = this // A 的 this
val b = this // B 的 this
val c = this // foo() 的接收者,一个 Int
val c1 = this // foo() 的接收者,一个 Int
val funLit = lambda@ fun String.() {
val d = this // funLit 的接收者
}
val funLit2 = { s: String ->
// foo() 的接收者,因为它包含的 lambda 表达式
// 没有任何接收者
val d1 = this
}
}
}
}注解
1
2
3
4
5
6annotation class Ann
class Example(
:Ann val foo: Int, // 标注 Java 字段
:Ann val bar: Int, // 标注 Java getter
:Ann val quux: Int
)反射
1
implementation("org.jetbrains.kotlin:kotlin-reflect:1.7.20")
KClasses 中定义了拓展反射方法
协程
1 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1") |
- runBlocking 方法会_阻塞_当前线程来等待
- coroutineScope 只是挂起,会释放底层线程用于其他用途
- runBlocking嵌套runBlocking ,被嵌套的runBlocking会让外部runBlocking阻塞
- Dispatchers.Unconfined 不会受到限制,直接执行,如果块内部调用了delay,阻塞完成后会切换线程
委托属性
- 延迟属性(lazy properties): 其值只在首次访问时计算;
- 可观察属性(observable properties): 监听器会收到有关此属性变更的通知;
- 把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中。