1、當(dāng)方法參數(shù)不定的時(shí)候,我們可以使用 vararg 聲明,這樣就可以傳入多個(gè)值了;但每個(gè)方法只能聲明一個(gè) vararg
fun printSum(vararg numbers: Int) {
val sum = numbers.sum()
print(sum)
}
printSum(1,2,3,4,5) // Prints: 15
printSum() // Prints: 0
// 可以直接傳遞數(shù)組(但是要以 * 為前綴)
val texts=arrayOf("b","c","d")
printAll(*texts)
2、當(dāng) when 的參數(shù)為空時(shí),可以省略 ()
// 這里省略了 `()`
override fun onOptionsItemSelected(item: MenuItem?)=when{
item?.itemId==R.id.design_menu_item_action_area->{
onBackPressed()
true
}
else -> super.onOptionsItemSelected(item)
}
3、Default arguments value versus Named arguments syntax
fun printValue(value: String, inBracket: Boolean = true,prefix: String = "", suffix: String = "") {
print(prefix)
if (inBracket) {
print("(${value})")
} else {
print(value)
}
println(suffix)
}
printValue("str", true, "","") // Prints: (str)
printValue("str") // Prints: (str)
printValue("str", false) // Prints: st
//命名式參數(shù)
printValue("str", suffix = "!") // Prints: (str)!
四、Top-level function
使用 Android 項(xiàng)目,Kotlin 被編譯成運(yùn)行在 Dalvik 上的 Java 字節(jié)碼。虛擬機(jī)(安卓 5.0 之前)或安卓運(yùn)行時(shí)(安卓 5.0 及更高版本)。兩個(gè)虛擬機(jī)都只能執(zhí)行類內(nèi)定義的代碼。為了解決這個(gè)問(wèn)題,Kotlin 編譯器為頂級(jí)函數(shù)生成類。這個(gè)類名由 文件名 和 kt 后綴構(gòu)成。在這樣的 class 里函數(shù)和屬性是靜態(tài)的。例如,假設(shè)我們定義了 printer.kt 文件中的函數(shù):
// Printer.kt
fun printTwo() {
print(2)
}
將 kotlin 代碼編譯成 Java 字節(jié)碼。生成的字節(jié)碼將類似于下面的 Java 類生成的代碼:
//Java
public final class PrinterKt { // 1
public static void printTwo() { // 2
System.out.print(2); // 3
}
}
1、printerkt 是由
文件名和kt 后綴組成的名稱。
2、所有頂級(jí)函數(shù)和屬性都編譯為靜態(tài)方法和變量。
3、print 是一個(gè) kotlin 函數(shù),但由于它是一個(gè)內(nèi)聯(lián)函數(shù),因此它的調(diào)用被替換為
它在編譯期間的主體。它的主體只包含 system.out.println 的調(diào)用
我們還可以在 Java 文件中訪問(wèn) Kotlin 頂級(jí)函數(shù)。用類名前綴函數(shù)調(diào)用:
//Java file, call inside some method
PrinterKt.printTwo()
正如我們所看到的,Kotlin 與 Java 是可以互操作的。為了使 Kotlin 的頂級(jí)方法,在 Java 中使用更加方便,我們可以添加一個(gè)可以更改名稱的 annotation (這個(gè)注解一定要放在 package 的上面) 一個(gè) JVM 生成的類。這樣在 Java 中調(diào)用 Kotlin 的頂級(jí)方法和屬性是很方便的。類似下面這樣:
@file:JvmName("Printer")
接著就可以在 Java 文件使用了。Printer.printTwo()
五、Local functions(局部方法)
fun makeStudentList(): List<Student> {
var students: List<Student> = emptyList()
fun addStudent(name: String, state: Student.State = Student.State.New) {
students += Student(name, state, courses = emptyList())
}
// ...
addStudent("Adam Smith")
addStudent("Donald Duck")
// ...
return students
}
這樣寫有一個(gè)好處就是,可以直接使用當(dāng)前方法的變量,不需要去傳遞;如果把它提取為成員方法,那就需要傳遞所需要的參數(shù),如果調(diào)用修改了參數(shù)的形式,那函數(shù)的聲明也需要重新修改,這樣就導(dǎo)致了要修改兩個(gè)地方(Java 中經(jīng)常出現(xiàn)這樣的問(wèn)題)。
六、自定義 getter/setter
class Student {
var age: Int?//自定義 get/set 方法
get() = age
set(value) {//value 是自定義的變量名,名字可以隨便起
age = value
}
}

這樣會(huì)爆出堆棧錯(cuò)誤?。?!讓我們來(lái)看一下 Student 的 class 文件

果然,造成了堆棧溢出(recursive call)
這時(shí)候使用 Kotlin 提供的備用字段(關(guān)鍵字 field)即可解決這個(gè)問(wèn)題
class Student {
var age: Int? = 0
get() = field //使用備用字段自定義 get/set 方法
set(value) {
field = value
}
}
再次查看 class 文件發(fā)現(xiàn)代碼也正常了

備用字段
field的使用范圍僅限于當(dāng)前屬性的get/set方法。
以下兩種情況不支持 field (寫了也沒效果)字段
① 因?yàn)榈谝淮晤悇?chuàng)建的時(shí)候,屬性的值就被計(jì)算了(后續(xù)的值不會(huì)再起作用)
class Fruit(var weight: Double) {
val isHeavy = weight > 20
}
var fruit = Fruit(7.0)
println(fruit.isHeavy) // Prints: false
fruit.weight = 30.5
println(fruit.isHeavy) // Prints: false
② 因?yàn)樗闹悼偸鞘褂昧硪粋€(gè)屬性計(jì)算的。
class Car {
var usable: Boolean = true
var inGoodState: Boolean = true
var crashed: Boolean
get() = !usable && !inGoodState
set(value) {
usable = false
inGoodState = false
}
}
如果類沒有主構(gòu)造函數(shù),而超類有一個(gè)非空的構(gòu)造函數(shù),然后每個(gè)次構(gòu)造函數(shù)必須使用 super 關(guān)鍵:
class ProductView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs : AttributeSet) super(ctx, attrs)
}