每種編程語(yǔ)言都有一定的語(yǔ)法、語(yǔ)義和執(zhí)行順序(同步),學(xué)習(xí)一種新語(yǔ)言也都是從這三者出發(fā),下面我們就只針對(duì)kotlin的語(yǔ)法來(lái)做簡(jiǎn)單的介紹。
Kotlin有自己的特性不該被Java的思維所束縛。
基本語(yǔ)法準(zhǔn)則:
在Kotlin中常量用 val 聲明,變量用 var 聲明;
關(guān)鍵字在前面,類(lèi)型以冒號(hào) :隔開(kāi)在后面,也可以省略直接賦值;
類(lèi)型后帶問(wèn)號(hào) ? 表示可為空類(lèi)型(默認(rèn)空類(lèi)型安全);
常量 val 延遲加載 by lazy{} ;
默認(rèn)是線程安全的,關(guān)閉線程安全 lazy(LazyThreadSafetyMode.NONE){} ;
變量 var 延遲加載 lateinit ;
內(nèi)部類(lèi)和參數(shù)默認(rèn)為public,而在Java中為private
類(lèi)默認(rèn)為不可繼承(final),想要可被繼承要聲明為 open 或 abstract
取消了static關(guān)鍵字,靜態(tài)方法和參數(shù)統(tǒng)一寫(xiě)在 companion object 塊
internal模塊內(nèi)可見(jiàn),inner內(nèi)部類(lèi)
//常量數(shù)組int[][][] arrs = new int[3][2][1];val arrs = Array(3) { Array(2) { IntArray(1) } }internal var name: String? = null//類(lèi)型后帶問(wèn)號(hào) ? 表示可為空類(lèi)型(默認(rèn)空安全)internal var age: Int = 0//internal模塊內(nèi)可見(jiàn),inner內(nèi)部類(lèi)//當(dāng)我們只有單個(gè)構(gòu)造器時(shí),我們需要在從父類(lèi)繼承下來(lái)的構(gòu)造器中指定需要的參數(shù)。這是用來(lái)替換Java中的super調(diào)用的。open class Animal(name: String)class Person(name: String, surname: String) : Animal(name)
kotlin是空類(lèi)型安全的,所有變量默認(rèn)為"not null",必須顯式在類(lèi)型后添加?修飾符才可賦值為null。
var notNullArtist: Artist = null//編譯不通過(guò),因?yàn)閚otNullArtist不能為nullvar artist: Artist? = null//編譯通過(guò)artist.print()//編譯不通過(guò),因?yàn)閍rtist可能為空/ Kotlin進(jìn)行空判斷處理,有兩種處理方式: 1. 拋出空異常,字段后加 !! 2. 不做處理直接跳過(guò),字段后加 ? /artist?.print()//編譯通過(guò),做了非空判斷,只有當(dāng)artist!=null時(shí)才調(diào)用print()artist!!.print()//這種用法只有在確認(rèn)artist不為null時(shí)才能調(diào)用,否則拋出空指針異常val name = artist?.name?:"empty"//當(dāng)artist為null時(shí)可以指定一個(gè)默認(rèn)值
條件語(yǔ)句
if...else 正常使用,不過(guò)移除了 switch 用更強(qiáng)大的 when 替代,when子式可以是各種返回Boolean的表達(dá)式
val x = 7when (x) {in 1..5 -> 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")}
kotlin盡可能多的使用when
循環(huán)語(yǔ)句
while 和 do...while 同Java并無(wú)區(qū)別, for 則有很大改變并多出了幾個(gè)變種
fun main(args: Array) { var list = ArrayList() add(list) list.forEachIndexed { i, s -> print(list[i]) print(s) } println() //如果沒(méi)有指定函數(shù)的返回值,它就會(huì)返回Unit,與Java中的void類(lèi)似,但是Unit是一個(gè)真正的對(duì)象。當(dāng)然也可以指定任何其它的返回類(lèi)型: list.forEachIndexed(object :(Int,String) -> Unit{ override fun invoke(i: Int, s: String) { print(list[i]) print(s) }})}//遞增for (int i = 0; i < list.size(); i++)for (i in list.indices) { print(list[i])}//遞增for (int i = 2; i < list.size(); i++)for (i in 2..list.size-1) { print(list[i])}//遞減for (int i = list.size(); i >= 0; i--)for (i in list.size downTo 0) { print(list[i])}//操作列表內(nèi)的對(duì)象for (item in list) { print(item)}//加強(qiáng)版for((i,item) in list.withIndex()){ print(list[i]) print(item)}//變種版list.forEach { print(it)}list.forEachIndexed { i, s -> print(list[i]) print(s)}list.forEachIndexed(object :(Int,String) -> Unit{ override fun invoke(i: Int, s: String) { print(list[i]) print(s) }})fun add(list:MutableList) { for (i in 0..4) { list.add(i.toString() + "") } }
冒號(hào)使用
在Kotlin中冒號(hào) : 用萬(wàn)能來(lái)稱(chēng)呼絕不為過(guò)。常量變量的類(lèi)型聲明,函數(shù)的返回值,類(lèi)的繼承都需要它
除此之外還有一個(gè)特別的地方也需要它,使用Java類(lèi)的時(shí)候。Kotlin最終會(huì)還是編譯成Java字節(jié)碼,使用到Java類(lèi)是必然的,在Kotlin語(yǔ)法如下
val intent = Intent(this, MainActivity::class.java)
指定上下文的@
除了冒號(hào)另一個(gè)重要符號(hào) @ ,java代碼中經(jīng)常用到內(nèi)部類(lèi)和匿名內(nèi)部類(lèi),有時(shí)我們不能確定this指代的上下文,Java可以使用XXX.this指代具體上下文,在kotlin中的做法是this@XXX
class User { inner class State{ fun getUser(): User{ //返回User return this@User } fun getState(): State{ //返回State return this@State } }}
kotlin的特色
Java的 getter/setter 方法自動(dòng)轉(zhuǎn)換成屬性,對(duì)應(yīng)到Kotlin屬性的調(diào)用
public class User { private String name; private String age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; }}
對(duì)應(yīng)的kotlin
val user = User()//賦值user.name = "tutu"user.age = "23"//取值val name = user.nameval age = user.ageclass User { var name: String? = null var age: String? = null}
有時(shí) getter/setter 方法比較復(fù)雜,這就需要自定義 getter/setter 了,實(shí)現(xiàn)一個(gè)Java中常用的單例,這里只為了展示,單例在Kotlin有更簡(jiǎn)單的方法實(shí)現(xiàn),只要在 package 級(jí)別創(chuàng)建一個(gè) object 即可
class User { companion object {//靜態(tài)方法和參數(shù)統(tǒng)一寫(xiě)在 companion object 塊 @Volatile var instance: User? = null get() { if (field == null) { synchronized(User::class.java) { if (field == null) field = User() } } return field } } var name: String? = null var age: String? = null}
自定義 getter/setter 重點(diǎn)在 field ,跟我們熟悉所Java的 this 指代當(dāng)前類(lèi)一樣, field 指代當(dāng)前參數(shù),直接使用參數(shù)名 instance 代替不會(huì)報(bào)錯(cuò)但單例就沒(méi)效果了
字符串問(wèn)題
在Java中拼接字符串的代碼可讀性都很差,在Kotlin字符串拼接變得非常簡(jiǎn)潔,只需用 $ 后面加上參數(shù)名,復(fù)雜的參數(shù)要加上 {}
val pair = Pair(1, "one") val (num, name) = pair println("num = $num, name = $name")
輸出num = 1, name = one
Java8新特性lambda的支持
接口名、方法名和參數(shù)類(lèi)型
lambda需要一個(gè)函數(shù),但是又不想費(fèi)神去命名一個(gè)函數(shù)的場(chǎng)合下使用,也就是指匿名函數(shù)。使用功能接口,把省掉不寫(xiě)再加個(gè) -> 罷了。
使用Java開(kāi)發(fā)Android時(shí),處理監(jiān)聽(tīng)回調(diào)是常見(jiàn)的事,kotlin可以直接編寫(xiě)監(jiān)聽(tīng)回調(diào)而不用再通過(guò)匿名對(duì)象傳遞onClick方法,這個(gè)特性被稱(chēng)為L(zhǎng)ambda表達(dá)式
view.setOnclickListener({ Toast.makeText(this, "Hello World!", Toast.LENGTH_LONG).show()})
擴(kuò)展函數(shù)
可以為任何已經(jīng)存在的類(lèi)添加新函數(shù),相比傳統(tǒng)工具類(lèi),擴(kuò)展函數(shù)更具有可讀性。
//為Fragment添加擴(kuò)展函數(shù)fun Fragment.toast(message: CharSequence, duration: Int = Toast.LENGTH_LONG){ Toast.makeText(getActivity(), message, duration).show()}
調(diào)用時(shí)直接調(diào)用fragment.toast("Hello World!")或fragment.toast("Hello World!", 2000)
Kotlin中的參數(shù)與Java中有些不同。如你所見(jiàn),我們先寫(xiě)參數(shù)的名字再寫(xiě)它的類(lèi)型。上面調(diào)用的第二個(gè)參數(shù)(length)指定了一個(gè)默認(rèn)值。這意味著你調(diào)用的時(shí)候可以傳入第二個(gè)值或者不傳,這樣可以避免你需要的重載函數(shù)。
函數(shù)式支持(lambda),函數(shù)是一級(jí)公民
參考文獻(xiàn)
Kotlin for android Developers
kotlin 腳本練習(xí)
新聞熱點(diǎn)
疑難解答
圖片精選