Kotlin基礎(chǔ)語法篇

自從實習(xí)結(jié)束后直到現(xiàn)在將近一年多的時間再也沒有用過kotlin殊者,

在今年五月份I/O大會上付秕,Google再次明確了Kotlin在Android開發(fā)中的地位豪治,并毫無懸念的將這個“后生晚輩”定為官方“首選”語言局齿,這使得Kotlin不得不被“傳統(tǒng)java

開發(fā)者”重視养铸,他們是時候改擁抱變化了,所以我們項目主要技術(shù)負(fù)責(zé)人現(xiàn)在勉強接受大家使用Kotlin開發(fā)意愿(實在不容易~)戒悠。

對荒廢了一年的語言現(xiàn)在重新拾起感覺又熟悉又陌生熬荆,但內(nèi)心還是很興奮的,最近準(zhǔn)備系統(tǒng)地整理一下Kotlin相關(guān)內(nèi)容救崔, 希望能在短時間內(nèi)重新掌握惶看,今天主要重新梳理一下Kotlin基礎(chǔ)語法捏顺。

Kotlin語言介紹

Kotlin 是 JetBrains 在 2010 年推出的基于 JVM 的新編程語言六孵,是一種新的靜態(tài)類型編程語言。開發(fā)者稱幅骄,設(shè)計它的目的是避免 Java 語言編程中的一些難題劫窒。比如:在 Kotlin 中類型系統(tǒng)控制了空指針引用,可以有效避免 Java 中常見的NullPointException拆座。

相比于 Java主巍,Kotlin 有著更好的語法結(jié)構(gòu)冠息,安全性和開發(fā)工具支持。

Kotlin 中沒有基礎(chǔ)類型孕索,數(shù)組是定長的逛艰,泛型是安全的,即便運行時也是安全的搞旭。此外散怖,該語言支持閉包吼驶,還可通過內(nèi)聯(lián)進(jìn)行優(yōu)化涩澡。不過尘颓,它不支持檢查異常(Checked Exceptions)搁嗓,許多語言設(shè)計者認(rèn)為這是它的瑕疵布朦。不論如何请敦,重要的是 Java 和 Kotlin 之間的互操作性:Kotlin 可以調(diào)用 Java贸营,反之亦可贾漏。

Kotlin基于JVM的字節(jié)碼結(jié)構(gòu)(與java同屬靜態(tài)語言)惑申,Kotlin 應(yīng)用程序的運行速度與 Java 類似具伍。,但隨著 Kotlin 對內(nèi)聯(lián)函數(shù)的支持圈驼,使用 lambda 表達(dá)式的代碼通常比用 Java 寫的代碼運行得更快沿猜。

Kotlin 可與 Java 進(jìn)行 100% 的互操作,允許在 Kotlin 應(yīng)用程序中使用所有現(xiàn)有的 Android 庫 碗脊,這包括注解處理啼肩,Google官方也說過未來Android支持庫優(yōu)先支持Kotlin語言;

Kotlin屬于跨平臺編譯語言衙伶,除了可以進(jìn)行原聲開發(fā)外很好的支持Java服務(wù)端程序開發(fā)祈坠、Android應(yīng)用程序開發(fā)以及JavaScript開發(fā);

Kotlin安裝與配置這里省略(網(wǎng)上很多教程矢劲,AndroidStudio3.x版本默認(rèn)已支持Kotlin插件)

基礎(chǔ)數(shù)據(jù)類型


Kotlin 的基本數(shù)據(jù)類型包括 Byte赦拘、Short、Int芬沉、Float躺同、Long、Double 丸逸、Boolean,

在java中基本數(shù)據(jù)類型一共有八種分別包括整形:byte蹋艺、short、int黄刚、long捎谨,浮點型:float、double , 字符型 char

以及布爾型 boolean涛救,不同于 Java 的是畏邢,Kotlin 字符不屬于數(shù)值類型,是一個獨立的數(shù)據(jù)類型,

大家可以看出Kotlin的基本數(shù)據(jù)類型和java不一樣检吆,Kotlin 中其實沒有基礎(chǔ)數(shù)據(jù)類型舒萎,只有封裝的對象類型,你每定義的一個變量蹭沛,其實

Kotlin 幫你封裝了一個對象逆甜,這樣可以保證不會出現(xiàn)空指針,

對應(yīng)Java中八大基本數(shù)據(jù)類型的對象類型、java在使用基礎(chǔ)數(shù)據(jù)類型時候可以通過裝箱操作封裝成對象致板;

字符

和 Java 不一樣交煞,Kotlin 中的 Char 不能直接和數(shù)字操作(可以通過顯示轉(zhuǎn)換char.toInt()),Char 必需是單引號 ' 包含起來的斟或。比如普通字符 '0'素征,'a',字符字面值用單引號括起來: '1'萝挤。 特殊字符可以用反斜杠轉(zhuǎn)義御毅。 支持這幾個轉(zhuǎn)義序列:\t、 \b怜珍、\n端蛆、\r、\'酥泛、\"今豆、\\ 和 \$。

當(dāng)需要可空引用時柔袁,像數(shù)字呆躲、字符會被裝箱。裝箱操作不會保留同一性捶索。

布爾

?????? 布爾用 Boolean 類型表示插掂,它有兩個值:true 和 false。當(dāng)需要可空引用布爾會被裝箱腥例。

數(shù)組

????? 數(shù)組用Array類實現(xiàn)辅甥,具有size屬性、get燎竖、setf方法璃弄,由于使用 [] 重載了 get 和 set 方法,所以我們可以通過下標(biāo)很方便的獲取或者設(shè)置數(shù)組對應(yīng)位置的值底瓣。java中素組具有l(wèi)ength屬性以及使用[]通過下標(biāo)方式訪問屬性谢揪;

數(shù)組的創(chuàng)建兩種方式:一種是使用函數(shù)arrayOf();另外一種是使用工廠函數(shù)捐凭。如下所示拨扶,我們分別是兩種方式創(chuàng)建了兩個數(shù)組:

fun main(args: Array<String>) {

? ? //[1,2,3]

? ? val a = arrayOf(1, 2, 3)

? ? //讀取數(shù)組內(nèi)容

? ? println(a[0])? ? // 輸出結(jié)果:1

? ? println(b[1])? ? // 輸出結(jié)果:2

}

val x: IntArray = intArrayOf(1, 2, 3

除了類Array,還有ByteArray, ShortArray, IntArray茁肠,LongArray等用來表示各個類型的數(shù)組患民,省去了裝箱操作,因此效率更高垦梆,其用法同Array一樣:

字符串

和java一樣,String屬于不可變的托猩,Kotlin可以通過[]很方便訪問對應(yīng)下標(biāo)字符印蓖,java中通過chatAt方法或者subString等方式獲取對應(yīng)字符,Kotlin中String支持遍歷形式訪問其中的字符京腥,這一點很使用赦肃;

for (c in str) {

? ? println(c)

}

另外Kotlin 支持三個引號 """ 擴(kuò)起來的字符串,支持多行字符串公浪,比如:

fun main(args: Array<String>) {

? ? val text = """多行字符串 多行字符串"""

? ? println(text)? // 輸出

}

String 可以通過 trim(),trimEnd(),trimStart(),trimMargin() 等方法來刪除多余的空白他宛。

類型轉(zhuǎn)換

java中可以通過隱式類型轉(zhuǎn)換,數(shù)值大的類型可以轉(zhuǎn)換成數(shù)據(jù)小的類型欠气,但是這樣往往會丟失精度厅各,在kotlin中由于不同的表示方式,較小類型并不是較大類型的子類型预柒,較小的類型不能隱式轉(zhuǎn)換為較大的類型队塘。

這意味著在不進(jìn)行顯式轉(zhuǎn)換的情況下我們不能把 Byte 型值賦給一個 Int 變量,

val b: Byte = 1 // OK, 字面值是靜態(tài)檢測的

val i: Int = b.toInt() // OK

每種數(shù)據(jù)類型都有下面的這些方法宜鸯,可以轉(zhuǎn)化為其它的類型:

toByte(): Byte

toShort(): Short

toInt(): Int

toLong(): Long

toFloat(): Float

toDouble(): Double

toChar(): Char

2. 變量人灼、常量聲明

定義只讀變量使用關(guān)鍵字val定義,只能為其賦值一次顾翼,

val a: Int = 1? // 立即賦值 (非空屬性必須在定義時候初始化投放,)

val b = 2? // 自動推斷出 `Int` 類型? (非空屬性必須在定義時候初始化,)

可重新賦值的變量使用var關(guān)鍵字:

var x = 5 // 自動推斷出 `Int` 類型 (非空屬性必須在定義時候初始化适贸,)

x += 1

Kotlin語法支持類型自動推斷灸芳,在聲明變量或者常量的時候可以不用指定其類型,編譯器在編譯時候會為我們指定其類型拜姿;

非空屬性必須在定義的時候初始化,kotlin提供了一種可以延遲初始化的方案,使用 lateinit 關(guān)鍵字描述屬性:

var count:Int?=null //可空屬性可以在后面賦值

count=5

lateinit var name : String 非空屬性使用延遲初始化

函數(shù)定義

函數(shù)定義使用fun關(guān)鍵字烙样,參數(shù)格式為 參數(shù):類型 ,最后函數(shù)返回值類型蕊肥,如下

fun sum( a:Int, b:Int):Int{return a+b}

亦可以函數(shù)表達(dá)式聲明函數(shù)

fun sum( a:Int, b:Int)=? a+b? // 自動類型推斷或者 fun sum(a:Int,b:Int):Int=a+b?

無返回值的函數(shù)定義(類似Java中的void):

fun printSum(a: Int, b: Int): Unit {

? ? print(a + b)

}

Unit返回類型可以省略:

public fun printSum(a: Int, b: Int) {

? ? print(a + b)

}

3. 可變長參數(shù)函數(shù)

可變長參數(shù)用vararg關(guān)鍵字進(jìn)行修飾:

fun print(vararg v:Int){?

? ? ? ? for(a in v){?

? ? ? ? ? ? println("$a")

? ? ? ? }

}

4. 字符串模板

$ 表示一個變量名或者變量值

$varName 表示變量值

${varName.fun()} 表示變量的方法返回值:

var a = 1

// 模板中的簡單名稱:

val s1 = "a is $a"

a = 2

// 模板中的任意表達(dá)式:

val s2 = "${s1.replace("is", "was")}, but now is $a"

// 運行結(jié)果:a was 1, but now is 2

5. 條件表達(dá)式

看一個常用if表達(dá)式:

fun value(a:Int, b :Int):Int {

? if(a>b) {

? ? return a+b?

? }else{?

? ? return a-b? ?

? }

}

通過條件表達(dá)式可以:

fun value(a:Int,b:Int)=if(a>b) a+b else a-b

6. NULL檢查機(jī)制

Kotlin的空安全設(shè)計對于聲明可為空的參數(shù)谒获,在使用時要進(jìn)行空判斷處理蛤肌,有兩種處理方式,字段后加!!像Java一樣拋出空異常批狱,另一種字段后加?可不做處理返回值為 null或配合?:做空判斷處理

//類型后面加?表示可為空

var age: String? = "23"

//拋出空指針異常

val ages = age!!.toInt()

//不做處理返回 null

val ages1 = age?.toInt()

//age為空返回-1

val ages2 = age?.toInt() ?: -1

當(dāng)一個引用可能為 null 值時, 對應(yīng)的類型聲明必須明確地標(biāo)記為可為 null裸准。

Kotlin 的NULL機(jī)制旨在消除來自代碼空引用的危險,這在java語言中屬于最常見的陷阱之一赔硫,也就是訪問空引用的成員會導(dǎo)致空引用異常炒俱。經(jīng)常會拋出NullPointerException或簡稱NPE。

在Kotlin中經(jīng)常會有一些鏈?zhǔn)秸{(diào)用用法爪膊,安全調(diào)用在鏈?zhǔn)秸{(diào)用中很有用权悟,如:person?.class?.countName 如果調(diào)用鏈中任何一個屬性值出現(xiàn)null情況,調(diào)用鏈會直接返回null推盛,

后面屬性不會出現(xiàn)NPE異常峦阁。

如果相對非null值執(zhí)行某個操作,可以結(jié)合let操作符一起使用:

val listWithNulls: List<String?> = listOf("Kotlin", null)? ? ?

for (item in listWithNulls) {

? ? ? ? ? item?.let {?

? ? ? ? ? println(it) // 輸出 Kotlin 并忽略 null?

? ? }

}

同樣安全調(diào)用也可以出現(xiàn)在賦值的左側(cè)耘成,如果調(diào)用鏈中的任何一個接收者為空都會跳過賦值拇派,而右側(cè)的表達(dá)式根本不會求值:

person?.class?.mathTeacher = TeachManager.getTeacher()

7. Elvis 操作符

當(dāng)我們有一個可空的引用r時,我們可以說“如果r非空凿跳,我使用它件豌;否則使用某個非空的值x”:

val l: Int = if (b != null) b.length else -1

或者

fun value(a:Int,b:Int)=if(a>b) a+b else a-b

//條件表達(dá)式用法

除了完整的 if-表達(dá)式,這還可以通過 Elvis 操作符表達(dá)控嗜,寫作?:

val l = b?.length ?: -1

如果?:左側(cè)表達(dá)式非空茧彤,elvis 操作符就返回其左側(cè)表達(dá)式,否則返回右側(cè)表達(dá)式疆栏。請注意曾掂,當(dāng)且僅當(dāng)左側(cè)為空時,才會對右側(cè)表達(dá)式求值壁顶。

這種Elvis用法類似java語言中三元操作符珠洗;

public int value(int a,int b){return a>b?a+b :a-b}

等同于:

fun value(a:Int,b:Int)=if(a>b) a+b else a-b

val l = b?.length ?: -1

等同于:

final int l= b!=null? b.length : -1

8. 類型檢測及類型轉(zhuǎn)換

如果對象不是目標(biāo)類型,那么常規(guī)類型轉(zhuǎn)換可能會導(dǎo)致ClassCastException若专,

val aInt: Int? = a as Int

為了避免類型轉(zhuǎn)成異常许蓖,另一個選擇是使用安全的類型轉(zhuǎn)換,如果嘗試轉(zhuǎn)換不成功則返回 null:

val aInt: Int? = a as? Int

或者

val sInt :Int?= if(a is Int) a as Int else null

或者

val sInt :Int?= if(a is Int) a else null

is 運算符檢測一個表達(dá)式是否某類型的一個實例(類似于Java中的instanceof關(guān)鍵字), 如果一個不可變的局部變量或?qū)傩砸呀?jīng)判斷出為某類型调衰,那么檢測后的分支中可以直接當(dāng)作該類型使用膊爪,無需顯式轉(zhuǎn)換:

fun getStringLength(obj: Any): Int? {

? if (obj is String) {

? ? // 做過類型判斷以后,obj會被系統(tǒng)自動轉(zhuǎn)換為String類型

? ? return obj.length

? }

? // 這里的obj仍然是Any類型的引用

? return null

}

或者

fun getStringLength(obj: Any): Int? {

? if (obj !is String)

? ? return null

? // 在這個分支中, `obj` 的類型會被自動轉(zhuǎn)換為 `String`

? return obj.length

}

9. 可空類型的集合

如果你有一個可空類型元素的集合嚎莉,并且想要過濾掉空元素米酬,你可以使用filterNotNull來實現(xiàn):

val listOf = listOf<Int?>(1, 2, null, 4)

val intList: List<Int> = listOf.filterNotNull()

10. 區(qū)間

區(qū)間表達(dá)式由具有操作符形式 .. 的 rangeTo 函數(shù)輔以 in 和 !in 形成。

使用 in 運算符來檢測某個數(shù)字是否在指定區(qū)間內(nèi):

for (i in 1..4) print(i) // 輸出“1234”

for (i in 4..1) print(i) // 什么都不輸出

if (i in 1..10) { // 等同于 1 <= i && i <= 10

? ? println(i)

}

// 使用 step 指定步長

for (i in 1..4 step 2) print(i) // 輸出“13”

for (i in 4 downTo 1 step 2) print(i) // 輸出“42”

// 使用 until 函數(shù)排除結(jié)束元素

for (i in 1 until 10) {? // i in [1, 10) 排除了 10

? ? println(i)

}

val list = listOf("a", "b", "c")

if (-1 !in 0..list.lastIndex) {

? ? println("-1 is out of range")

}

if (list.size !in list.indices) {

? ? println("list size is out of valid list indices range, too")

}

11. 使用 for 循環(huán)

for 循環(huán)可以對任何提供迭代器(iterator)的對象進(jìn)行遍歷趋箩,語法如下:

同樣赃额,kotlin的for循環(huán)中使用的也是in操作符加派,

val items = listOf("dog", "cat", "pig")

for (item in items) {

println(item)

}

或者通過索引

val items = listOf("apple", "banana", "kiwifruit")

for (index in items.indices) {

? ? println("item at $index is ${items[index]}")

}

val array=arrayOf("a","b","c")

for (i in array.indices) {

? ? print(array[i])

}

12. 使用 when 表達(dá)式

when 將它的參數(shù)和所有的分支條件順序比較,直到某個分支滿足條件跳芳,

when 既可以被當(dāng)做表達(dá)式使用也可以被當(dāng)做語句使用芍锦。如果它被當(dāng)做表達(dá)式,符合條件的分支的值就是整個表達(dá)式的值筛严,如果當(dāng)做語句使用醉旦, 則忽略個別分支的值饶米。

when 類似java語言的 switch 操作符桨啃。其最簡單的形式如下:

fun describe(obj: Any): String =

when (obj) {

1? ? ? ? ? -> "One"

"Hello"? ? -> "Greeting"

is Long? ? -> "Long"

!is String -> "Not a string"

else? ? ? -> "Unknown"

}

在Kotlin中Any類是所有類的超類,類似java中的Object檬输;

在 when 中照瘾,else 同 switch 的 default。如果其他分支都不滿足條件將會求值 else 分支丧慈。如果很多分支需要用相同的方式處理析命,則可以把多個分支條件放在一起,用逗號分隔逃默。

when 也可以用來取代 if-else if鏈鹃愤。 如果不提供參數(shù),所有的分支條件都是簡單的布爾表達(dá)式完域,而當(dāng)一個分支的條件為真時則執(zhí)行該分支:

when {

? ? x.isOdd() -> print("x is odd")

? ? x.isEven() -> print("x is even")

? ? else -> print("x is funny")

}

13. 使用 lambda 表達(dá)式來過濾(filter)與映射(map)集合

val fruits = listOf("banana", "avocado", "apple", "kiwifruit")

fruits.filter { it.startsWith("a") }

.sortedBy { it }

.map { it.toUpperCase() }

.forEach { println(it) }

結(jié)果:APPLE AVOCADO

14. 類以及構(gòu)造器

類的修飾符包括 classModifier 和_accessModifier_:

classModifier: 類屬性修飾符软吐,標(biāo)示類本身特性。

abstract? ? // 抽象類?

final? ? ? // 類不可繼承吟税,默認(rèn)屬性

enum? ? ? ? // 枚舉類

open? ? ? ? // 類可繼承凹耙,類默認(rèn)是final的

annotation? // 注解類

accessModifier: 訪問權(quán)限修飾符

private? ? // 僅在同一個文件中可見

protected? // 同一個文件中或子類可見

public? ? // 所有調(diào)用的地方都可見

internal? // 同一個模塊中可見

主構(gòu)造器(主構(gòu)造函數(shù))

Koltin 中的類可以有一個 主構(gòu)造器,以及一個或多個次構(gòu)造器肠仪,主構(gòu)造器是類頭部的一部分肖抱,位于類名稱之后:

class Person constructor(firstName: String) {}

如果主構(gòu)造器沒有任何注解,也沒有任何可見度修飾符异旧,那么constructor關(guān)鍵字可以省略意述。

class Person(firstName: String) {

}

主構(gòu)造器中不能包含任何代碼,初始化代碼可以放在初始化代碼段中吮蛹,初始化代碼段使用 init 關(guān)鍵字作為前綴欲险。

class Person constructor(firstName: String) {

? ? init {

? ? ? firstName="Scus"? //主構(gòu)造器的參數(shù)可以在初始化代碼段中使用

? ? }

}

另外可以通過主構(gòu)造器來定義屬性并初始化屬性值(可以是var或val):

class People(val firstName: String, val lastName: String) {

? ? //...

}

如果一個非抽象類沒有聲明構(gòu)造函數(shù)(主構(gòu)造函數(shù)或次構(gòu)造函數(shù)),它會產(chǎn)生一個沒有參數(shù)的構(gòu)造函數(shù)匹涮。構(gòu)造函數(shù)是 public 天试。如果你不想你的類有公共的構(gòu)造函數(shù),你就得聲明一個空的主構(gòu)造函數(shù):

class DontCreateMe private constructor () {

}

次構(gòu)造函數(shù)

類也可以有二級構(gòu)造函數(shù)然低,需要加前綴 constructor:

class Person(val name: String) {

? ? constructor (name: String, age:Int) : this(name) {

? ? ? ? // 初始化...

? ? }

}

抽象類

抽象是面向?qū)ο缶幊痰奶卣髦幌裁浚惐旧砦裉疲蝾愔械牟糠殖蓡T,都可以聲明為abstract的带兜。抽象成員在類中不存在具體的實現(xiàn)枫笛。

注意:無需對抽象類或抽象成員標(biāo)注open注解。

open class Base {

? ? open fun f() {}

}

abstract class Derived : Base() {

? ? override abstract fun f()

}

嵌套類

我們可以把類嵌套在其他類中刚照,看以下實例:

class Outer {? ? ? ? ? ? ? ? ? // 外部類

? ? private val bar: Int = 1

? ? class Nested {? ? ? ? ? ? // 嵌套類

? ? ? ? fun foo() = 2

? ? }

}

匿名內(nèi)部類

使用對象表達(dá)式來創(chuàng)建匿名內(nèi)部類:

? ? test.setInterFace(object : TestInterFace {

? ? ? ? override fun test() {

? ? ? ? ? ? println("對象表達(dá)式創(chuàng)建匿名內(nèi)部類的實例")

? ? ? ? }

? ? })

內(nèi)部類

內(nèi)部類使用 inner 關(guān)鍵字來表示刑巧。

內(nèi)部類會帶有一個對外部類的對象的引用,所以內(nèi)部類可以訪問外部類成員屬性和成員函數(shù)无畔。

class Outer {

? ? private val bar: Int = 1

? ? var v = "成員屬性"

? ? /**嵌套內(nèi)部類**/

? ? inner class Inner {

? ? ? ? fun foo() = bar? // 訪問外部類成員

? ? ? ? fun innerTest() {

? ? ? ? ? ? var o = this@Outer //獲取外部類的成員變量

? ? ? ? ? ? println("內(nèi)部類可以引用外部類的成員啊楚,例如:" + o.v)

? ? ? ? }

? ? }

}

數(shù)據(jù)類

Kotlin 可以創(chuàng)建一個只包含數(shù)據(jù)的類,關(guān)鍵字為 data:

data class User(val name: String, val age: Int)

密封類

密封類用來表示受限的類繼承結(jié)構(gòu):當(dāng)一個值為有限幾種的類型, 而不能有任何其他類型時浑彰。在某種意義上恭理,他們是枚舉類的擴(kuò)展:枚舉類型的值集合 也是受限的,但每個枚舉常量只存在一個實例郭变,而密封類 的一個子類可以有可包含狀態(tài)的多個實例颜价。

聲明一個密封類,使用 sealed 修飾類诉濒,密封類可以有子類周伦,但是所有的子類都必須要內(nèi)嵌在密封類中。

sealed class Expr

data class Const(val number: Double) : Expr()

data class Sum(val e1: Expr, val e2: Expr) : Expr()

object NotANumber : Expr()

fun eval(expr: Expr): Double = when (expr) {

? ? is Const -> expr.number

? ? is Sum -> eval(expr.e1) + eval(expr.e2)

? ? NotANumber -> Double.NaN

}

15. 接口

Kotlin 接口與 Java 8 類似未荒,使用 interface 關(guān)鍵字定義接口专挪,允許方法有默認(rèn)實現(xiàn):

interface MyInterface {

? ? fun bar() // 未實現(xiàn)? ?

? ? fun foo() {//已實現(xiàn)? ? ?

? ? ? ? println("foo")?

? ? }

}

一個類或者對象可以實現(xiàn)一個或多個接口。

class Child : MyInterface {

? ? override fun bar() {

? ? ? ? // 方法體

? ? }

? ? override fun fool() {

? ? ? ? // 方法體

? ? }

}

接口中的屬性只能是抽象的茄猫,不允許初始化值狈蚤,接口不會保存屬性值,實現(xiàn)接口時划纽,必須重寫屬性:

interface MyInterface{

? ? var name:String //name 屬性, 抽象的

}

class MyImpl:MyInterface{

? ? override var name: String = "runoob" //重寫屬性

}

16. Kotlin 繼承

kotlin 中所有類都繼承該 Any 類脆侮,它是所有類的超類,對于沒有超類型聲明的類是默認(rèn)超類:

如果一個類要被繼承勇劣,可以使用 open 關(guān)鍵字進(jìn)行修飾靖避。

open class Base(p: Int)? ? ? ? ? // 定義基類

class Derived(p: Int) : Base(p)

注意:Any 不是 java.lang.Object。

如果子類有主構(gòu)造函數(shù)比默, 則基類必須在主構(gòu)造函數(shù)中立即初始化幻捏。

open class Person(var name : String, var age : Int){// 基類

}

class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {

}

如果子類沒有主構(gòu)造函數(shù),則必須在每一個二級構(gòu)造函數(shù)中用 super 關(guān)鍵字初始化基類命咐,或者在代理另一個構(gòu)造函數(shù)篡九。初始化基類時,可以調(diào)用基類的不同構(gòu)造方法醋奠。

class Student : Person {

? ? constructor(ctx: Context) : super(ctx) {

? ? }

? ? constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {

? ? }

}

在基類中榛臼,使用fun聲明函數(shù)時伊佃,此函數(shù)默認(rèn)為final修飾,不能被子類重寫沛善。如果允許子類重寫該函數(shù)航揉,那么就要手動添加 open 修飾它,。

17.對象聲明

Kotlin 使用 object 關(guān)鍵字來聲明一個對象金刁。

Kotlin 中我們可以方便的通過對象聲明來獲得一個單例帅涂。

object DataProviderManager {

? ? fun registerDataProvider(provider: DataProvider) {

? ? ? ? // ……

? ? }

? ? val allDataProviders: Collection<DataProvider>

? ? ? ? get() = // ……

}

引用該對象,我們直接使用其名稱即可:

DataProviderManager.registerDataProvider(……)

當(dāng)然你也可以定義一個變量來獲取獲取這個對象尤蛮,當(dāng)你定義兩個不同的變量來獲取這個對象時媳友,你會發(fā)現(xiàn)你并不能得到兩個不同的變量,也就是說通過這種方式抵屿,我們獲得一個單例:如

object Site {

? ? var url:String = ""

? ? val name: String = "菜鳥教程"

}

fun main(args: Array<String>) {

? ? var s1 =? Site

? ? var s2 = Site

? ? s1.url = "www.runoob.com"

? ? println(s1.url)

? ? println(s2.url)

}

// 輸出結(jié)果都為"www.runnoob.com"

18.伴生對象

類內(nèi)部的對象聲明可以用 companion 關(guān)鍵字標(biāo)記庆锦,這樣它就與外部類關(guān)聯(lián)在一起捅位,我們就可以直接通過外部類訪問到對象的內(nèi)部元素轧葛。

class MyClass {

? ? companion object Factory {

? ? ? ? fun create(): MyClass = MyClass()

? ? }

}

val instance = MyClass.create()? // 訪問到對象的內(nèi)部元素

我們可以省略掉該對象的對象名,然后使用 Companion 替代需要聲明的對象名:

class MyClass {

? ? companion object {

? ? }

}

注意:一個類里面只能聲明一個內(nèi)部關(guān)聯(lián)對象艇搀,即關(guān)鍵字 companion 只能使用一次尿扯。

伴生對象的成員看起來像java的靜態(tài)成員,但在運行時他們?nèi)匀皇钦鎸崒ο蟮膶嵗蓡T焰雕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衷笋,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子矩屁,更是在濱河造成了極大的恐慌辟宗,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吝秕,死亡現(xiàn)場離奇詭異泊脐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)烁峭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門容客,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人约郁,你說我怎么就攤上這事缩挑。” “怎么了鬓梅?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵供置,是天一觀的道長。 經(jīng)常有香客問我绽快,道長芥丧,這世上最難降的妖魔是什么悲关? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮娄柳,結(jié)果婚禮上寓辱,老公的妹妹穿的比我還像新娘。我一直安慰自己赤拒,他們只是感情好秫筏,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著挎挖,像睡著了一般这敬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蕉朵,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天崔涂,我揣著相機(jī)與錄音,去河邊找鬼始衅。 笑死冷蚂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的汛闸。 我是一名探鬼主播蝙茶,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼诸老!你這毒婦竟也來了隆夯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤别伏,失蹤者是張志新(化名)和其女友劉穎蹄衷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厘肮,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡愧口,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了轴脐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片调卑。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖大咱,靈堂內(nèi)的尸體忽然破棺而出恬涧,到底是詐尸還是另有隱情,我是刑警寧澤碴巾,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布溯捆,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏提揍。R本人自食惡果不足惜啤月,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望劳跃。 院中可真熱鬧谎仲,春花似錦、人聲如沸刨仑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杉武。三九已至辙诞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轻抱,已是汗流浹背飞涂。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留祈搜,地道東北人较店。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像夭问,于是被迫代替她去往敵國和親泽西。 傳聞我的和親對象是個殘疾皇子曹铃,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容