1、在 Kotlin 中類可以有屬性,我們可以使用 :
1.1、var 關鍵字聲明可變屬性:
var x = 5 // `Int` type is inferred
x += 1
1.2、val 關鍵字聲明隻讀屬性:
val a: Int = 1 // 立刻指派
val b = 2 // `Int` 類型是自推導的
val c: Int // 沒有初始化器時要指定類型
c = 3 // 推導型指派
2、空安全
2.1、"?" -> 聲明為可空的變量
var b: String? = "abc"
b = null
2.2、"?." -> 如果 b 不為空則傳回長度,否則傳回空。這個表達式的的類型是 Int?
b?.length()
2.3、"?:" -> 如果 "?:" 左邊表達式不為空則傳回,否則傳回右邊的表達式。(注意:右邊的表帶式隻有在左邊表達式為空是才會執行)
val l = b.length()?: -1
2.4、"!!" -> 傳回一個非空的 b 值 或者如果 b 為空,就會抛出一個 NPE(空指針) 異常:
val l = b!!.length
2.5、"=="與"===" -> "=="判斷值是否相等,"==="判斷值及引用是否完全相等。
val num: Int = 128;
val a:Int? = num
val b:Int? = num
println(a == b)
print(a === b)
3、Kotlin常用操作符
3.1、"?:" Elvis操作符
如果 "?:" 左邊表達式非空,elvis操作符就會傳回左邊的結果,否則傳回右邊的結果。請注意,僅在左側為空的時候,右側的表達式才會計算
val a = b?.length?:-1
//等同于:
val a: Int = if(b != null) b.length else -1
3.2、"as?" 安全轉換
當使用 as 轉型的時候,可能會經常出現 ClassCastException。 是以,現在可以使as?安全轉型,當轉型不成功的時候,它會傳回 null。
注:在使用intent傳值的時候,會出現空字元串不能用as強制轉型,這是應該使用as?
val m: Int? = a as? Int
3.3、":" 冒号 用于類的繼承,變量的定義
1、類型和超類型之間的冒号前要有一個空格
2、執行個體和類型之間的冒号前不要空格
//定義全局變量時
var str: String? = null
//類的繼承與變量定義
class TestActivity<T : Serializable>(str: String) : Activity{}
3.4、"is" 類型判斷符
檢查某個執行個體是否是某個類型,如果判斷出屬于某個類型,那麼判斷後的分支中可以直接可當該類型使用,無需顯示轉換
fun getStringLength(obj: Any): Int? {
//obj在&&右邊自動動轉換成"String"類型
if (obj is String && obj.length > 0)
return obj.length
return null
}
3.5、".."、"until" 操作符 以及 "in" 和 "!in" 操作符
".." 代表從x到y,包括x和y,這是一個閉區間運算符,而
"until" 則是半閉區間運算符,代表從a到b範圍内所有的值,包括a和不包括b。
"in" 代表在一個區間中,"!in" 代表不在一個區間中。
if (i in 1..10) { // 等價于 1 <= i && i <= 10
println(i)
}
//使用until函數,建立一個不包括其結束元素的區間
for (i in 1 until 10) { // i in [1, 10) 排除了 10
println(i)
}
3.5.1、downTo()函數
//區間内循環:
for (i in 4 downTo 1){
print(i) //倒叙周遊
}
// print “4321”
3.5.2、step()函數 可以進行任意數量的疊代,而不是每次變化都是1
for (i in 1..4 step 2) print(i) // prints "13"
for (i in 4 downTo 1 step 2) print(i) // prints "42"
3.6、多行輸入符 三個雙引号
三引号的形式用來輸入多行文本,也就是說在三引号之間輸入的内容将被原樣保留,之中的單号和雙引号不用轉義,其中的不可見字元比如/n和/t都會被保留
val str = """
one
two
"""
//等價于
val str = "one\ntwo"
val str = "one" +"\n"+"two"
3.7、"::"符号 得到類的Class對象
startActivity(Intent([email protected], MainActivity::class.java))
3.8、"@"符号
3.8.1、限定this的類型
class User {
inner class State{
fun getUser(): User{
//傳回User
return [email protected]
}
fun getState(): State{
//傳回State
return [email protected]
}
}
}
3.8.2、作為标簽(見4.6詳解)
3.9、"$"操作符
字元串可以包含模闆表達式,及一小段代碼,會求值并把結果包含到字元串中。模闆字元串以美元符号$開頭,由一個簡單的名字構成:
val value:Int=5;
val str:String="the value is $value"
println("itemB:$itemB")
//字元串模闆
var userInfo = "name:${user.name}, age:$age"
或花括号括起來的任意表達式
val g:Int=2
val h:Int=3
val str:String="g+h=${g+h}"
轉義字元串和原生字元串都支援模闆字元串。如果想要在原生字元串中使用$(它不支援反斜杠轉義),可以使用以下文法:
val str:String="""the price is ${'$'}199"""
4、條件表達式的使用
4.1、"if/else" 語句規則:
①if後的括号不能省略,括号裡表達式的值最終必須傳回的是布爾值
②如果條件體内隻有一條語句需要執行,那麼if後面的大括号可以省略,但這是一種極為不好的程式設計習慣。
③對于給定的if,else語句是可選的,else if 語句也是可選的
④else和else if同時出現時,else必須出現在else if 之後
⑤如果有多條else if語句同時出現,那麼如果有一條else if語句的表達式測試成功,那麼會忽略掉其他所有else if和else分支。
⑥如果出現多個if,隻有一個else的情形,else子句歸屬于最内層的if語句
4.1.1、傳統用法
val a = 10
val b = 20
var max_0: Int = a
if (a > b) {
max_0 = a
} else {
max_0 = b
}
println("----------------------------------")
println("max_0:$max_0")
println("----------------------------------")
// Log
--------------
max_0:20
--------------
4.1.2、作為表達式
var max_1 = if (a > b) a else b
println("--------------")
println("max_1:$max_1")
println("--------------")
//Log
--------------
max_1:20
--------------
4.1.3、作為代碼塊
println("--------------")
val max_2 = if (a > b) {
println("Choose a")
a
} else {
println("Choose b")
b
}
println("max_2:$max_2")
println("--------------")
// Log
--------------
Choose b
max_2:20
--------------
if 作為代碼塊時,最後一行必須為該塊的傳回值.
如果 if 表達式隻有一個分支, 或者分支的結果是 Unit , 它的值就是 Unit 。
4.2、"when"
when會對所有的分支進行檢查直到有一個條件滿足。 when 可以用做表達式或聲明。
如果用作表達式的話,那麼滿足條件的分支就是總表達式。
如果用做聲明,不滿足條件的分支的的的值會被忽略,隻保留滿足條件的分支,而且傳回的值也是最後一個表達式的值。
4.2.1、傳統用法
val x : Int = 10
when (x) {
9 -> println("x:${x + 10}")
10 -> println("x:$x")
else -> print("x:$x")
}
4.2.2、分支條件一緻
如果有分支可以用同樣的方式處理的話, 分支條件可以連在一起處理。
when (x) {
0,1 -> print("x == 0 or x == 1")//同樣的方式處理
else -> print("otherwise")
}
4.2.3、使用任意表達式作為分支的條件
when (x) {
parseInt(s) -> print("s encode x")
else -> print("s does not encode x")
}
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
4.2.4、作為表達式
val hasPrefix = when (x) {
is String -> x.startsWith("prefix")
else -> false
}
4.3、"for"
for 循環通過任何提供的疊代器進行疊代。 文法如下:
for (item in collection)
print(item)
//如果周遊list或者array可以通過索引進行疊代:
for (i in array.indices)
print(array[i])
4.4、"while" 循環
4.4.1、"while"語句:while語句在循環剛開始時,會計算一次布爾表達式的值,如果滿足條件,進入循環,
如果不滿足條件,将跳出循環。而在while語句的下一次疊代開始前會計算再一次布爾值,如此重複。
while (x > 0) {
x--
}
4.4.2、"dowhile"語句:dowhile語句與while語句類似,唯一的差別是doWhile語句會至少執行一次,即便布爾表達式的第一次計算就是false。而while語句中,如果 布爾表達式的第一次計算的值是false,該循環不會執行。
4.5、傳回與跳轉 Kotlin中有"return"、"break"、"continue"等三種傳回跳轉操作符。
4.5.1、"return" ①指定一個方法傳回什麼值 ②導緻目前方法結束,并傳回傳回指定的值
fun main(args: Array<String>) {
println("testA:${testA(10)}")
println("----------")
println("testB:${testB(10)}")
}
fun testA(a : Int):Int{
if (a > 0) {
return -1
} else {
return 1
}
}
fun testB(a : Int):Int{
println("a:$a")
if (a > 0) {
return -1
} else {
return 1
}
a++
print("a:$a")
}
// Log列印
testA:-1
----------
a:10
testB:-1
4.5.2、"break" 結束最近的閉合循環,不執行循環中剩餘的語句
val arraysA = listOf("A", "B", "C", "D")
val arraysB = listOf(1,2,3,4)
for (itemA in arraysA) {
for (itemB in arraysB) {
if (itemB > 2) {
break
}
println("itemB:$itemB")
}
if (itemA == "C") {
break
}
println("itemA:$itemA")
}
// Log
itemB:1
itemB:2
itemA:A
itemB:1
itemB:2
itemA:B
itemB:1
itemB:2
從Log列印可以看出,第一個break結束的是for (itemB in arraysB)這個循環,
而第二個break結束的是for (itemA in arraysA),它們的共通點就是結束都是距離它們最近的一個循環。
4.5.3、"continue" 跳到最近的閉合循環的下一次循環
val arraysA = listOf("A", "B", "C", "D")
val arraysB = listOf(1,2,3,4)
for (itemA in arraysA) {
var i : Int = 0
for (itemB in arraysB) {
i++
if (itemB > 2) {
continue
}
println("itemB:$itemB")
}
if (itemA == "C") {
continue
}
println("i:$i")
println("itemA:$itemA")
println("---------")
}
// Log
itemB:1
itemB:2
i:4
itemA:A
---------
itemB:1
itemB:2
i:4
itemA:B
---------
itemB:1
itemB:2
itemB:1
itemB:2
i:4
itemA:D
---------
從上述Log上,可以清楚看到,兩個循環分别循環了四次,但是在碰到continue時,會跳出目前循環并執行下一次循環。
4.6、标簽 在 Kotlin 中表達式可以添加标簽,标簽通過@結尾來表示,比如:[email protected],[email protected]
[email protected] for (i in 1..100){
//...
}
4.6.1、"break"和标簽
val arraysA = listOf("A", "B", "C", "D")
val arraysB = listOf(1,2,3,4)
[email protected] for (itemA in arraysA) {
var i : Int = 0
for (itemB in arraysB) {
i++
if (itemB > 2) {
[email protected]
}
println("itemB:$itemB")
}
println("i:$i")
println("itemA:$itemA")
println("---------")
}
// Log列印
itemB:1
itemB:2
從Log列印,第一個循環執行了一次,第二個循環執行了兩次,便跳出了封閉的循環。
意味着break跳到标簽後邊的表達式,并不再執行此表達式直接跳過,執行後邊的語句。
4.6.2、"continue"和标簽
val arraysA = listOf("A", "B", "C", "D")
val arraysB = listOf(1,2,3,4)
[email protected] for (itemA in arraysA) {
var i : Int = 0
for (itemB in arraysB) {
i++
if (itemB > 2) {
[email protected]
}
println("itemB:$itemB")
}
println("i:$i")
println("itemA:$itemA")
println("---------")
}
// Log列印
itemB:1
itemB:2
itemB:1
itemB:2
itemB:1
itemB:2
itemB:1
itemB:2
之前說過,continue是跳到最近的閉合循環的下一次循環,但是加上标簽以後,直接跳轉到了第一個循環,也就是for (itemA in arraysA),
并沒有執行最近的閉合循環的下一次循環。意味着continue直接跳轉到标簽後面的語句并執行。
4.6.3、"return"和标簽
val ints = listOf(0, 1, 2, 3)
fun main(args: Array<String>) {
foo()
}
fun foo() {
ints.forEach {
if (it ==0) [email protected]
println(it)
}
}
// Log列印
1
2
3
從Log列印可以看出,return會跳轉到标簽後邊的表達式處,并執行該表達式。
4.6.4、命名函數自動定義标簽
foo outer() {
foo inner() {
[email protected]
}
}
4.6.5、作用域
val ints = listOf(0, 1, 2, 3)
fun main(args: Array<String>) {
[email protected]
foo()
}
fun foo() {
ints.forEach {
if (it ==0) [email protected]
println(it)
}
//return @list//這麼調用會報錯,會提示“Unresolved reference:@list”
}
從作用域來看,标簽和變量是一緻的,都有相對應的作用域。在main方法裡面定義了一個标簽[email protected],在foo方法裡面調用時,
提示“Unresolved reference:@list”,意味着list标簽的作用域應該在main方法裡,在foo方法裡并不能夠調用。
感謝
https://github.com/huanglizhuo/kotlin-in-chinese
http://blog.csdn.net/IO_Field/article/details/52842596
http://blog.csdn.net/jhj_24/article/details/53887820