Kotlin 是基于 JVM 的语言。它提供了许多语法糖来替代 Java 中的一些操作。如果 Java 做不到的功能,Kotlin 也做不到。Kotlin 源代码执行时都会被编译为Java字节码,IDE中可以使用 Tool -> Kotlin->Show Kotlin Bytecode
查看自己的代码将会被编译之后的样子,然后使用IDE的 Decompile
反编译成java源码查看,就知道Kotlin代码实际对应的Java代码了。
部分内容吸取自 https://github.com/heimashi/kotlin_tips
字符串
1 2 3 4
| val str1 = "abcd" val str2 = """ {"name":"tom", "age": 20} """.trimIndent()
|
发编译为Java:
1
| String str2 = StringsKt.trimIndent("\n {\"name\":\"tom\", \"age\": 20}\n ");
|
1 2 3
| data class User(val name: String, val age: Int) val user = User("tom", 20) println("${user.name}'s age is ${user.age}")
|
反编译为Java:
1 2 3
| User user = new User("tom", 20); String var7 = "" + user.getName() + "'s age is " + user.getAge(); System.out.println(var7);
|
如果要想显示 $
符,需要使用反斜杠 \
转义
控制结构 -> 表达式
- 表达式有返回值,可以作为其他表达式的一部分
- 控制结构,编程语句,负责包围代码块,本身没有值
if 表达式
1 2 3
| fun max(a: Int, b: Int): Int { return if (a > b) a else b }
|
反编译为Java:
1 2 3
| public final int max(int a, int b) { return a > b ? a : b; }
|
when 表达式
可替换 switch 和 if-else 语句
简化 switch
1 2 3 4 5 6 7
| fun getDesc(value: Int) = when (value) { 90 -> "GOOD" 80 -> "OK" 70 -> "GOON" 60 -> "Simple" else -> "DEFAULT" }
|
反编译的Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public final String getDesc(int value) { String var10000; switch(value) { case 60: var10000 = "Simple"; break; case 70: var10000 = "GOON"; break; case 80: var10000 = "OK"; break; case 90: var10000 = "GOOD"; break; default: var10000 = "DEFAULT"; } return var10000; }
|
简化 if-else
1 2 3 4 5
| fun getDesc2(value: Int) = when { value >= 90 -> "GOOD" value in 60..80 -> "OK" else -> "BAD" }
|
反编译的Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public final String getDesc2(int value) { String var10000; if (value >= 90) { var10000 = "GOOD"; } else { if (60 <= value) { if (80 >= value) { var10000 = "OK"; return var10000; } } var10000 = "BAD"; } return var10000; }
|
函数和属性扩展
函数扩展
1 2 3 4 5
| fun String.title(): String { return if (length < 1) this else substring(0, 1).toUpperCase() + substring(1, length) }
println("abc".title())
|
反编译的Java:
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
| public static final String title(@NotNull String $receiver) { String var10000; if ($receiver.length() < 1) { var10000 = $receiver; } else { StringBuilder var7 = new StringBuilder(); byte var2 = 0; byte var3 = 1; StringBuilder var4 = var7; var10000 = $receiver.substring(var2, var3); String var5 = var10000; if (var5 == null) { throw new TypeCastException("null cannot be cast to non-null type java.lang.String"); } var10000 = var5.toUpperCase(); var5 = var10000; var7 = var4.append(var5); var2 = 1; int var6 = $receiver.length(); var4 = var7; var10000 = $receiver.substring(var2, var6); var5 = var10000; var10000 = var4.append(var5).toString(); } return var10000; }
|
可以看到,通过在当前类里实现一个静态方法,接受被扩展类的实例对象,然后构造一个新的对象,执行扩展的操作。
属性扩展
1 2 3 4 5 6 7 8
| val String.title: String get() { return if (length < 1) this else this.substring(0, 1).toUpperCase() + substring(1, length) }
println("abc".title)
println("abc".getTitle())
|
给 String 增加一个 title
属性,在 get
里实现扩展的逻辑
懒初始化 by lazy, 延迟初始化 lateinit
by lazy
首次使用的时候才会执行
lateinit
推迟一个变量的初始化
lazy
方法默认会添加同步锁,保证线程安全,在你确保是单线程访问的情况下, 使用 LazyThreadSafetyMode.NONE
可以避免同步的开销 。可以传递一个 LazyMode 手动指定模式
1 2 3 4 5 6
| public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> = when (mode) { LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer) LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer) LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer) }
|
1 2 3 4 5
| lateinit var a: String
val b: String by lazy { "abc" }
|
by lazy
只能用于 val
不可变对象
lateinit
只能用于 var
可变对象
lateinit
不能用于原始类型 Int
Float
Short
Byte
Char
这些
数据类
使用 data
声明
1
| data class User(val name: String, val age: Int)
|
使用 data
关键字声明一个类是数据类,会自动生成模板代码。
注:当构造函数里有 Array
等数组类类型时,需要单独实现 equals
和 hashCode
方法
getXXX
setXXX
(如果参数定义是可变的 var
)
copy
toString
equals
hashCode
自动生成的数据类:
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
| public final class User { @NotNull private final String name; private final int age;
@NotNull public final String getName() { return this.name; }
public final int getAge() { return this.age; }
public User(@NotNull String name, int age) { Intrinsics.checkParameterIsNotNull(name, "name"); super(); this.name = name; this.age = age; }
@NotNull public final String component1() { return this.name; }
public final int component2() { return this.age; }
@NotNull public final User copy(@NotNull String name, int age) { Intrinsics.checkParameterIsNotNull(name, "name"); return new User(name, age); }
public String toString() { return "User(name=" + this.name + ", age=" + this.age + ")"; }
public int hashCode() { return (this.name != null ? this.name.hashCode() : 0) * 31 + this.age; }
public boolean equals(Object var1) { if (this != var1) { if (var1 instanceof User) { User var2 = (User)var1; if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) { return true; } } return false; } else { return true; } }
|
不加 data
声明
不加 data
,只声明 class
,会自动为字段生成 getter
和 setter
方法。
1
| class User(val name: String, var age: Int?)
|
自动生成的Java:
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
| public final class User { @NotNull private final String name; @Nullable private Integer age;
@NotNull public final String getName() { return this.name; }
@Nullable public final Integer getAge() { return this.age; }
public final void setAge(@Nullable Integer var1) { this.age = var1; }
public User(@NotNull String name, @Nullable Integer age) { Intrinsics.checkParameterIsNotNull(name, "name"); super(); this.name = name; this.age = age; } }
|
Null 安全
Kotlin 默认定义的对象都是不能为空的,可以使用 ?
定义可空对象。如果将 null
赋给一个不能为空的对象,会触发编译期异常,从而避免了运行时 NullPointerException
;如果调用一个可空对象的方法,必需增加非空判断或者使用 ?.
或 !!.
运算符,否则会触发编译器异常。
?.
如果对象为空,将不会执行后续操作
!!.
如果对象为空,将会抛出 NullPointerException
1 2 3 4 5 6 7
| val a: String? = null
fun t() { a.substring(0) a?.substring(0) a!!.substring(0) }
|