
本文同步更新于旺仔的個(gè)人博客,訪問(wèn)可能有點(diǎn)慢,多刷新幾次。
Kotlin中有一些常用的關(guān)鍵字和標(biāo)識(shí)符,同時(shí)還有一些操作符和特殊符號(hào),這些都是和Java有不一樣的地方的,這里將他們介紹一下,方便記憶和回看。
硬關(guān)鍵字(Hard Keywords)
Kotlin中的硬關(guān)鍵字不能作為標(biāo)識(shí)符
package
與Java一樣,Kotlin的源文件同樣以包聲明開(kāi)始的。
package foo.bar
fun baz() {}
class Goo {}
// ...
interface
interface表示聲明一個(gè)接口,
interface MyInterface {
fun bar()
fun foo() {
// 可選的方法體
}
}
class
Kotlin的類的聲明與Java一樣,使用class關(guān)鍵字
class Invoice {
}
object
object為同時(shí)聲明一個(gè)類及其實(shí)例,請(qǐng)看對(duì)象表達(dá)式。
super
具體內(nèi)容可看Kotlin學(xué)習(xí)_類和繼承、接口與實(shí)現(xiàn)。
引用一個(gè)方法或?qū)傩缘某悓?shí)現(xiàn)
open class Foo {
open fun f() { println("Foo.f()") }
open val x: Int get() = 1
}
class Bar : Foo() {
override fun f() {
super.f()
println("Bar.f()")
}
override val x: Int get() = super.x + 1
}
在此構(gòu)造函數(shù)中調(diào)用超類構(gòu)造函數(shù)
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
null
null是表示不指向任何對(duì)象的對(duì)象引用的常量。
this
在次構(gòu)造函數(shù)(二級(jí)構(gòu)造函數(shù))中調(diào)用同一個(gè)類中的另一個(gè)構(gòu)造函數(shù)。
class Person(val name: String) {
constructor(name: String, paret: Person) : this(name) {
parent.children.add(this)
}
constructor(name: String, parent: Person, count: Int) : this(name) {
parent.children.add(this)
}
}
typealias
類型別名為現(xiàn)有類型提供替代名稱。如果類型名稱太長(zhǎng),您可以引入不同的較短的名稱,并使用新的名稱。
縮短長(zhǎng)泛型類型:
typealias NodeSet = Set<Network.Node>
typealias FileTable<K> = MutableMap<K, MutableList<File>>
可以為功能類型提供不同的別名:
typealias MyHandler = (Int, String, Any) -> Unit
typealias Predicate<T> = (T) -> Boolean
as
as是一個(gè)中綴操作符。
用于類型轉(zhuǎn)換
as是不安全的轉(zhuǎn)換操作符,如果as轉(zhuǎn)換失敗,會(huì)拋出一個(gè)異常,這就是不安全的。
val x: String = y as String
上面的代碼表示將y強(qiáng)轉(zhuǎn)為String類型,如果y為null,那么將不能轉(zhuǎn)換成String,因?yàn)?code>String是不可空的類型,那么就會(huì)拋出一個(gè)異常,所以如果y的類型是可空類型的話,那么強(qiáng)轉(zhuǎn)的類型就必須是可空的
val x: String? = y as String?
用于指定導(dǎo)入包的別名
as除了用于類型轉(zhuǎn)換之外,還有一個(gè)作用就是可以指定導(dǎo)入包的別名
import foo.Bar // Bar 可訪問(wèn)
import bar.Bar as bBar // bBar 代表“bar.Bar”
as?
as?與as類似,也是轉(zhuǎn)換操作符,但是與as不同的是,as?是安全的,也就是可空的,可以避免拋出異常,在轉(zhuǎn)換失敗是會(huì)返回null
val x: String? = y as? String
as后面的類型是個(gè)可空的類型,而as?后面的類型確實(shí)非空類型,但是as?轉(zhuǎn)換的類型卻是可空的,這樣是主要的區(qū)別。
if和else
在Kotlin中,if表達(dá)式表示返回一個(gè)值(true或false),Kotlin中沒(méi)有三目運(yùn)算符。
而else與Java定義一樣,定義一個(gè)if表達(dá)式條件為false時(shí)執(zhí)行的分支。
//傳統(tǒng)用法
var max = a
if (a < b)
max = b
//帶 else
var max: Int
if (a > b)
max = a
else
max = b
//作為表達(dá)式
val max = if (a > b) a else b
true和false
指定布爾類型的"真"值和"假"值。
while和do
while是開(kāi)始一個(gè)while循環(huán)(前置條件的循環(huán)),而do為開(kāi)始一個(gè)do/while循環(huán)(后置條件的循環(huán)),do...while 與Java的一樣,有一個(gè)區(qū)別是,語(yǔ)句塊里面的變量在外面是可見(jiàn)的
while (x > 0) {
x--
}
do {
val y = retrieveData()
} while (y != null) // y 在這是可見(jiàn)的
for
for表示開(kāi)始一個(gè)for循環(huán)
for (item: Int in ints) {
// ...
}
when
Kotlin中的when就類似與Java的switch,但是與switch不同的是,when在其它分支都不匹配的時(shí)候默認(rèn)匹配 else 分支,如果沒(méi)有把所有可能和分支條件列出來(lái),那么else是強(qiáng)制的,這與switch的default也有區(qū)別。
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 默認(rèn)
print("x is neither 1 nor 2")
}
}
break
break用于終止循環(huán)的執(zhí)行,使用break 跳轉(zhuǎn)到標(biāo)簽處,跳出循環(huán)
loop@ for (i in 1..10) {
for (j in i..10) {
if (j == 5)
break@loop // 跳出循環(huán)
Log.e(Tag, j.toString()) // j 為5的時(shí)候跳出了循環(huán),只打印1、2、3、4
}
}
continue
continue用于跳到最近的閉合循環(huán)的下一次循環(huán)
loop@ for (i in 1..10) {
for (j in i..10) {
if (j == 5)
continue@loop // 跳出本次循環(huán),進(jìn)行下一次循環(huán)
Log.e(Tag, j.toString()) // j 為5的時(shí)候跳出了循環(huán),所有不會(huì)打印5
}
}
return
return默認(rèn)從最直接包圍它的函數(shù)或者匿名函數(shù)返回。
fun foo() {
ints.forEach {
if (it == 0) return // 跳出forEach
print(it)
}
}
fun
fun表示聲明一個(gè)函數(shù)
fun test() {
}
in
用于指定for循環(huán)中迭代的對(duì)象
for (item in collection) print(item)
用作中綴操作符以檢查一個(gè)值屬于一個(gè)區(qū)間、一個(gè)集合或者其他定義contains方法的實(shí)體。
if (i in 1..10) { // 等同于 1 <= i && i <= 10
println(i)
}
if(a in b){ // a in b等同于b.contains(a)
println("a in b")
}
在when中使用
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
else -> print("none of the above")
}
abstract class Comparable<in T> {
abstract fun compareTo(other: T): Int
}
fun demo(x: Comparable<Number>) {
x.compareTo(1.0) // 1.0 擁有類型 Double,它是 Number 的子類型
// 因此,我們可以將 x 賦給類型為 Comparable <Double> 的變量
val y: Comparable<Double> = x // OK!
}
!in
!in表示與in相反
用作中綴操作符以檢查一個(gè)值不屬于一個(gè)區(qū)間、一個(gè)集合或者其他定義contains方法的實(shí)體。
if (i !in 1..10) { // 表示i不在1到10區(qū)間
println(i)
}
if(a !in b){ // a !in b等同于!b.contains(a)
println("a !in b")
}
在when中使用
when (x) {
in 1..10 -> print("x is in the range")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
is和!is
是否符合給定類型
類似與Java的instanceOf,is操作符或其否定形式!is來(lái)檢查對(duì)象是否符合給定類型:
if (obj is String) {
print(obj.length)
}
if (obj !is String) { // 與 !(obj is String) 相同
print("Not a String")
}
else {
print(obj.length)
}
在when表達(dá)式中用于判定是否符合
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
throw和try
throw和try與Java定義一樣,throw為拋出一個(gè)異常,而try為捕獲異常。
throw MyException("Hi There!")
try {
// 一些代碼
}
catch (e: SomeException) {
// 處理程序
}
finally {
// 可選的 finally 塊
}
val
val表示聲明一個(gè)只讀屬性或局部變量
val name: String = ……
var
val表示聲明一個(gè)可變屬性或局部變量
var name: String = ……
軟關(guān)鍵字(Soft Keywords)
以下符號(hào)在適用的上下文中充當(dāng)關(guān)鍵字,而在其他上下文中可用作標(biāo)識(shí)符:
import
導(dǎo)入一個(gè)包里面的類文件
import foo.Bar // 導(dǎo)入foo包里面的Bar
by
將接口的實(shí)現(xiàn)委托給另一個(gè)對(duì)象
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).print() // 輸出 10
}
將屬性訪問(wèn)器的實(shí)現(xiàn)委托給另一個(gè)對(duì)象
class Example {
var p: String by Delegate()
}
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name} in $thisRef.'")
}
}
get
聲明屬性的getter
val isEmpty: Boolean
get() = this.size == 0
set
聲明屬性的setter
var stringRepresentation: String
get() = this.toString()
set (value) {
setDataFormString(value) // 格式化字符串,并且將值重新賦值給其他元素
}
dynamic
引用一個(gè)Kotlin/JS代碼中的動(dòng)態(tài)類型
val dyn: dynamic = ……
catch
與Java一樣,處理異常
try {
// 一些代碼
}
catch (e: SomeException) {
// 處理程序
}
finally
與Java一樣,try退出時(shí)總會(huì)執(zhí)行的塊
try {
// 一些代碼
}
catch (e: SomeException) {
// 處理程序
}
finally {
// 可選的 finally 塊
}
constructor
聲明一個(gè)主構(gòu)造函數(shù)或次構(gòu)造函數(shù)
class Person constructor(firstName: String) {
}
init
主構(gòu)造函數(shù)不能包含任何的代碼。初始化的代碼可以放到以init關(guān)鍵字作為前綴的初始化塊中:
class Customer(name: String) {
init {
logger.info("Customer initialized with value ${name}")
}
}
param、setparam、delegate、field、file、property
class Example(@field:Ann val foo, // 標(biāo)注 Java 字段
@get:Ann val bar, // 標(biāo)注 Java getter
@param:Ann val quux) // 標(biāo)注 Java 構(gòu)造函數(shù)參數(shù)
使用目標(biāo)(Use-site Targets)支持的有:
file-
property使用此目標(biāo)的注解對(duì)Java不可見(jiàn) field-
get屬性的getter -
set屬性的setter -
receiver擴(kuò)展函數(shù)或?qū)傩缘慕邮掌鲄?shù) -
param構(gòu)造函數(shù)參數(shù) -
setparam屬性的setter的參數(shù) -
delegate該字段存儲(chǔ)代理屬性的代理實(shí)例
receiver
where
whera用于指定泛型多個(gè)類型的上界約束
fun <T> cloneWhenGreater(list: List<T>, threshold: T): List<T>
where T : Comparable,
T : Cloneable {
return list.filter { it > threshold }.map { it.clone() }
}
修飾詞關(guān)鍵字(Modifier Keywords)
out
abstract class Source<out T> {
abstract fun nextT(): T
}
fun demo(strs: Source<String>) {
val objects: Source<Any> = strs // 這個(gè)沒(méi)問(wèn)題,因?yàn)?T 是一個(gè) out-參數(shù)
// ……
}
annotation
annotation表示聲明一個(gè)注解類
annotation class Fancy
companion
companion表示聲明一個(gè)伴生對(duì)象
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
const
const表示將屬性標(biāo)記為編譯期常量,可用于注解當(dāng)中
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { …… }
external
external表示將一個(gè)聲明標(biāo)記為不是在 Kotlin 中實(shí)現(xiàn)(通過(guò)JNI訪問(wèn)或者在 JavaScript中實(shí)現(xiàn))
// JNI
external fun foo(x: Int): Double
// JavaScript
external fun alert(message: Any?): Unit
external class Node {
val firstChild: Node
fun append(child: Node): Node
fun removeChild(child: Node): Node
// 等等
}
external val window: Window
inline
聲明一個(gè)函數(shù)為內(nèi)聯(lián)函數(shù)
inline fun lock<T>(lock: Lock, body: () -> T): T {
// ……
}
crossinline
crossinline表示禁止傳遞給內(nèi)聯(lián)函數(shù)的lambda中的非局部返回
inline fun f(crossinline body: () -> Unit) {
val f = object: Runnable {
override fun run() = body()
}
// ……
}
noinline
noinline表示一個(gè)內(nèi)聯(lián)函數(shù)如果只有一些被內(nèi)聯(lián),另外的不想內(nèi)聯(lián),可以將函數(shù)禁用內(nèi)聯(lián):
inline fun <T> T.one (inlined: () -> Unit, noinline notInlined: () -> Unit) {
}
如果一個(gè)內(nèi)聯(lián)函數(shù)沒(méi)有可內(nèi)聯(lián)的函數(shù)參數(shù)并且沒(méi)有具體化類型參數(shù),則會(huì)產(chǎn)生一個(gè)禁告,因?yàn)檫@樣的內(nèi)聯(lián)函數(shù)沒(méi)有什么用處。

final
final為禁止成員覆蓋。
open class AnotherDerived() : Base() {
final override fun v() {} // v方法不可被重寫(xiě)
}
open
允許一個(gè)類子類化或覆蓋成員,open與final相反,它允許其他類從這個(gè)類繼承,默認(rèn)情況下,在Kotlin中所有的類都是final
open class Base(p: Int)
class Derived(p: Int) : Base(p)
data
聲明一個(gè)類為數(shù)據(jù)類
data class User(val name: String, val age: Int)
abstract
與Java一樣,abstract將一個(gè)類或成員標(biāo)記為抽象
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
enum
聲明一個(gè)枚舉類
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
inner
聲明一個(gè)內(nèi)部類,允許在嵌套類中引用外部類實(shí)例
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}
val demo = Outer().Inner().foo() // == 1
sealed
聲明一個(gè)密封類(限制子類化的類)
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
lateinit
延遲初始化屬性,允許在構(gòu)造函數(shù)之外初始化非空屬性
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // 直接解引用
}
}
operator
將一個(gè)函數(shù)標(biāo)記為重載一個(gè)操作符,也就是操作符重載

override
與Java類型,override表示重寫(xiě),Derived.v() 函數(shù)上必須加上 override標(biāo)注。如果沒(méi)寫(xiě),編譯器將會(huì)報(bào)錯(cuò)。
open class Base {
open fun v() {}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
private
可見(jiàn)性,將一個(gè)聲明標(biāo)記為在當(dāng)前類或文件中可見(jiàn)
protected
可見(jiàn)性,將一個(gè)聲明標(biāo)記為在當(dāng)前類及其子類中可見(jiàn)
internal
可見(jiàn)性,將一個(gè)聲明標(biāo)記為在當(dāng)前模塊中可見(jiàn)
public
可見(jiàn)性,將一個(gè)聲明標(biāo)記為在任何地方可見(jiàn)
reified
suspend
將一個(gè)函數(shù)或lambda表達(dá)式標(biāo)記為掛起式(可用做協(xié)程)
suspend fun doSomething(foo: Foo): Bar {
……
}
infix
允許以中綴表示法調(diào)用函數(shù)
// 給 Int 定義擴(kuò)展
infix fun Int.shl(x: Int): Int {
……
}
// 用中綴表示法調(diào)用擴(kuò)展函數(shù)
1 shl 2
// 等同于這樣
1.shl(2)
tailrec
tailrec表示將一個(gè)函數(shù)標(biāo)記為尾遞歸(允許編譯器將遞歸替換為迭代)
private fun findFixPoint(): Double {
var x = 1.0
while (true) {
val y = Math.cos(x)
if (x == y) return y
x = y
}
}
vararg
vararg表示可變參數(shù)(通常是最后一個(gè)參數(shù)):
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts) // 在這里ts的類型是數(shù)組
result.add(t)
return result
}
使用:
val list = asList(1, 2, 3)
當(dāng)我們調(diào)用vararg函數(shù),不僅可以接收可以一個(gè)接一個(gè)傳遞參數(shù),例如asList(1, 2, 3),也可以將一個(gè)數(shù)組傳遞進(jìn)去,在數(shù)組變量前面加spread操作符,就是*號(hào):
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4) // 表示(-1, 0, 1, 2, 3, 4)
特殊標(biāo)識(shí)符(Special Identifiers)
field
field為備用字段,Kotlin中的類并不允許使用字段,在自定義getter和setter的時(shí)候,可以使用field來(lái)起到局部變量的作用。
var counter = 0 //初始化值會(huì)直接寫(xiě)入備用字段
get() = field
set(value) {
if (value >= 0)
field = value
}
編譯器會(huì)檢查訪問(wèn)器的代碼,如果使用了備用字段(或者訪問(wèn)器是默認(rèn)的實(shí)現(xiàn)邏輯),就會(huì)自動(dòng)生成備用字段,否則就不會(huì)。
// 這種情況并不需要備用字段,所有不會(huì)生成備用字段
val isEmpty: Boolean
get() = this.size == 0
注意:
field標(biāo)識(shí)符只允許在屬性的訪問(wèn)器函數(shù)內(nèi)使用.
it
it為單個(gè)參數(shù)的隱式名稱,若函數(shù)參數(shù)對(duì)應(yīng)的函數(shù)只有一個(gè)參數(shù),在使用時(shí),可以省略參數(shù)定義(連同->),直接使用it代替參數(shù):
val doubled = ints.map { it -> it * 2 }
ints.filter { it > 0 } // it表示 '(it: Int) -> Boolean'
這種方式可以寫(xiě)成LINQ-style代碼:
strings.filter { it.length == 5 }
.sortBy { it }
.map { it.toUpperCase() }
操作符和特殊符號(hào)(Operators and Special Symbols)
+、-、*、/、%
數(shù)學(xué)操作符,其中*還能用于將數(shù)組傳給vararg參數(shù)
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts) // ts is an Array
result.add(t)
return result
}
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
=
=除了作為賦值操作符外,還用于指定參數(shù)的默認(rèn)值
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
}
+=、-=、*=、/=、%=
廣義賦值操作符

++、--
遞增遞減操作符

&&、||、!
邏輯“與”、“或”、“非”操作符,對(duì)應(yīng)的中綴函數(shù)
-
and(bits)– 位與 -
or(bits)– 位或 -
xor(bits)– 位異或 -
inv()– 位非
==、!=
相等操作符,對(duì)于非原生類型會(huì)翻譯為調(diào)用equals()

===、!==
引用相等操作符,引用相等由===(以及其否定形式 !==)操作判斷。a === b 當(dāng)且僅當(dāng)a和b指向同一個(gè)對(duì)象時(shí)求值為true。
<、>、<=、>=
比較操作符,對(duì)于非原生類型會(huì)翻譯為調(diào)用compareTo()
[、]
索引訪問(wèn)操作符,會(huì)翻譯為調(diào)用get與set

!!
一個(gè)表達(dá)式非空
val l = b!!.length
?.
執(zhí)行安全調(diào)用,如果接收者非空,就調(diào)用一個(gè)方法或訪問(wèn)一個(gè)屬性
b?.length
?:
如果左側(cè)的值為空,就取右側(cè)的值(elvis操作符)
val l = b?.length ?: -1
::
創(chuàng)建一個(gè)成員引用或者一個(gè)類引用
fun isOdd(x: Int) = x % 2 != 0
val numbers = listOf(1, 2, 3)
println(numbers.filter(::isOdd)) // 輸出 [1, 3]
..
創(chuàng)建一個(gè)區(qū)間
val s = 1..10
?
將類型標(biāo)記為可空
val s: String? = null
->
分隔lambda表達(dá)式的參數(shù)與主體
val sum = { x: Int, y: Int -> x + y }
分隔在函數(shù)類型中的參數(shù)類型與返回類型聲明
// less類型是函數(shù)參數(shù)
fun <T> max(collection: Collection<T>, less: (T, T) -> Boolean): T? {
var max: T? = null
for (it in collection)
if (max == null || less(max, it))
max = it
return max
}
分隔 when 表達(dá)式分支的條件與代碼體
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x is neither 1 nor 2")
}
}
@
引入一個(gè)注解
@Fancy class Foo {
@Fancy fun baz(@Fancy foo: Int): Int {
return (@Fancy 1)
}
}
引入或引用一個(gè)循環(huán)標(biāo)簽
loop@ for (i in 1..100) {
for (j in 1..100) {
if (……) break@loop
}
}
引入或引用一個(gè)lambda表達(dá)式標(biāo)簽
fun foo() {
ints.forEach lit@ {
if (it == 0) return@lit
print(it)
}
}
引用一個(gè)來(lái)自外部作用域的 this表達(dá)式
class A { // 隱式標(biāo)簽 @A
inner class B { // 隱式標(biāo)簽 @B
fun Int.foo() { // 隱式標(biāo)簽 @foo
val a = this@A // A 的 this
val b = this@B // B 的 this
val c = this // foo() 的接收者,一個(gè) Int
val c1 = this@foo // foo() 的接收者,一個(gè) Int
val funLit = lambda@ fun String.() {
val d = this // funLit 的接收者
}
val funLit2 = { s: String ->
// foo() 的接收者,因?yàn)樗?lambda 表達(dá)式
// 沒(méi)有任何接收者
val d1 = this
}
}
}
}
引用一個(gè)外部超類
class Bar : Foo() {
override fun f() { /* …… */ }
override val x: Int get() = 0
inner class Baz {
fun g() {
super@Bar.f() // 調(diào)用 Foo 實(shí)現(xiàn)的 f()
println(super@Bar.x) // 使用 Foo 實(shí)現(xiàn)的 x 的 getter
}
}
}
;
分隔位于同一行的多個(gè)語(yǔ)句
map.forEach { _, value ->
println("$value!");println("$value!")
}
$
在字符串模版中引用變量或者表達(dá)式
val s = "abc"
val str = "$s.length is ${s.length}" // 求值結(jié)果為 "abc.length is 3"
_
在lambda表達(dá)式中代替未使用的參數(shù)
map.forEach { _, value ->
println("$value!")
}
在解構(gòu)聲明中代替未使用的參數(shù)
val (_, status) = getResult()