函數(shù)的定義
函數(shù)定義使用關(guān)鍵字fun ,參數(shù)格式為:參數(shù):類型
fun sun(a:Int,b:Int) :Int { // Int 參數(shù)楷拳,返回值 Int
return a+b;
}
表達(dá)式作為函數(shù)體阳掐,返回類型自動(dòng)推斷:
fun sum(a: Int, b: Int) = a + b
public fun sum(a: Int, b: Int): Int = a + b // public 方法則必須明確寫出返回類型
無返回值的函數(shù)(類似Java中的void):
fun printSum(a: Int, b: Int): Unit { //也可以不聲明返回值
print(a + b)
}
// 如果是返回 Unit類型垂攘,則可以省略(對(duì)于public方法也是這樣):
public fun printSum(a: Int, b: Int) {
print(a + b)
}
函數(shù)的變長(zhǎng)參數(shù)可以用 vararg 關(guān)鍵字進(jìn)行標(biāo)識(shí):
fun prin(vararg v:Int){
for(vt in v){
print(vt)
}
}
lambda表達(dá)式使用實(shí)例:
fun main(args: Array<String>) {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 輸出 3
}
定義常量與變量
可變變量定義:var 關(guān)鍵字
不可變變量定義:val 關(guān)鍵字,只能賦值一次的變量(類似Java中final修飾的變量)
val a: Int = 1
var a: Int = 1
字符串模板
varName 表示變量值
${varName.fun()} 表示變量的方法返回值
var a = 1
// 模板中的簡(jiǎn)單名稱:
val s1 = "a is {s1.replace("is", "was")}, but now is $a"
NULL檢查機(jī)制
//類型后面加?表示可為空
var age: String? = "23"
//拋出空指針異常
val ages = age!!.toInt()
//不做處理返回 null
val ages1 = age?.toInt()
//age為空返回-1
val ages2 = age?.toInt() ?: -1
NULL檢查機(jī)制
當(dāng)一個(gè)引用可能為 null 值時(shí), 對(duì)應(yīng)的類型聲明必須明確地標(biāo)記為可為 null视乐。
當(dāng) str 中的字符串內(nèi)容不是一個(gè)整數(shù)時(shí), 返回 null:拿到結(jié)果后再去判斷是否是等于null
fun parseInt(str: String): Int? {
// ...
}
類型檢測(cè)及自動(dòng)類型轉(zhuǎn)換
fun getStringLength(obj: Any): Int? {
if (obj is String) { //使用!is
// 做過類型判斷以后票灰,obj會(huì)被系統(tǒng)自動(dòng)轉(zhuǎn)換為String類型
return obj.length
}
// 這里的obj仍然是Any類型的引用
return null
}
區(qū)間
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 指定步長(zhǎng)
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 x = 5
if (x in 1..8) {
println("x 在區(qū)間內(nèi)")
}
基本數(shù)據(jù)類型
Kotlin 的基本數(shù)值類型包括 Byte待锈、Short、Int贫悄、Long株搔、Float耗啦、Double 等。不同于Java的是,字符char不屬于數(shù)值類型绅作,是一個(gè)獨(dú)立的數(shù)據(jù)類型。
8進(jìn)制不支持
Kotlin 中沒有基礎(chǔ)數(shù)據(jù)類型宽气,只有封裝的數(shù)字類型,,這樣可以保證不會(huì)出現(xiàn)空指針。數(shù)字類型也一樣淘捡,所有在比較兩個(gè)數(shù)字的時(shí)候,就有比較數(shù)據(jù)大小和比較兩個(gè)對(duì)象是否相同的區(qū)別了竭讳。
在 Kotlin 中,三個(gè)等號(hào) === 表示比較對(duì)象地址,兩個(gè) == 表示比較兩個(gè)值大小棘幸。
var a:Int =10000;
println(a === a) // true女嘲,值相等,對(duì)象地址相等
//經(jīng)過了裝箱,創(chuàng)建了兩個(gè)不同的對(duì)象
var boxedA:Int ?=a;
var anotherBoxedA:Int?=a;
//雖然經(jīng)過了裝箱册倒,但是值是相等的估灿,都是10000
println(boxedA === anotherBoxedA) // false,值相等犹褒,對(duì)象地址不一樣
println(boxedA == anotherBoxedA) // true削茁,值相等
如果boxedA ,anotherBoxedA 后面不接:Int 則地址也相等
類型轉(zhuǎn)換
由于不同的表示方式圃阳,較小類型并不是較大類型的子類型,較小的類型不能隱式轉(zhuǎn)換為較大的類型银萍。 這意味著在不進(jìn)行顯式轉(zhuǎn)換的情況下我們不能把 Byte 型值賦給一個(gè) Int 變量.
val b: Byte = 1 // OK, 字面值是靜態(tài)檢測(cè)的
val i: Int = b // 錯(cuò)誤
我們可以代用其toInt()方法飞袋。
val b: Byte = 1 // OK, 字面值是靜態(tài)檢測(cè)的
val i: Int = b.toInt() // OK
有些情況下也是可以使用自動(dòng)類型轉(zhuǎn)化的,前提是可以根據(jù)上下文環(huán)境推斷出正確的數(shù)據(jù)類型而且數(shù)學(xué)操作符會(huì)做相應(yīng)的重載。例如下面是正確的:
val l = 1L + 3 // Long + Int => Long
位操作符
shl(bits) – 左移位 (Java’s <<)
shr(bits) – 右移位 (Java’s >>)
ushr(bits) – 無符號(hào)右移位 (Java’s >>>)
and(bits) – 與
or(bits) – 或
xor(bits) – 異或
inv() – 反向
和 Java 不一樣锻拘,Kotlin 中的 Char 不能直接和數(shù)字操作,Char 必需是單引號(hào) ' 包含起來的击蹲。比如普通字符 '0'署拟,'a'。
數(shù)組
一種是使用函數(shù)arrayOf()歌豺;另外一種是使用工廠函數(shù)
//[1,2,3]
val a = arrayOf(1, 2, 3)
//[0,2,4]
val b = Array(3, { i -> (i * 2) })
//讀取數(shù)組內(nèi)容
println(a[0]) // 輸出結(jié)果:1
println(b[1]) // 輸出結(jié)果:2
// [] 運(yùn)算符代表調(diào)用成員函數(shù) get() 和 set()
//空數(shù)組推穷,可以用add添加數(shù)據(jù)
var bb = arrayListOf<Int>();
除了類Array,還有ByteArray, ShortArray, IntArray类咧,用來表示各個(gè)類型的數(shù)組馒铃,省去了裝箱操作,因此效率更高痕惋,其用法同Array一樣:
和 Java 一樣区宇,String 是不可變的。方括號(hào) [] 語(yǔ)法可以很方便的獲取字符串中的某個(gè)字符值戳,也可以通過 for 循環(huán)來遍歷:
Kotlin 支持三個(gè)引號(hào) """ 擴(kuò)起來的字符串议谷,支持多行字符串
String 可以通過 trimMargin() 方法來刪除多余的空白。
val price = """
'}9.99
"""
println(price) // 求值結(jié)果為 $9.99
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// 作為表達(dá)式
val max = if (a > b) a else b
when 類似其他語(yǔ)言的 switch 操作符
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意這個(gè)塊
print("x 不是 1 堕虹,也不是 2")
}
}
在 when 中卧晓,else 同 switch 的 default。如果其他分支都不滿足條件將會(huì)求值 else 分支赴捞。
如果很多分支需要用相同的方式處理逼裆,則可以把多個(gè)分支條件放在一起,用逗號(hào)分隔:
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
我們也可以檢測(cè)一個(gè)值在(in)或者不在(!in)一個(gè)區(qū)間或者集合中:
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")
}
另一種可能性是檢測(cè)一個(gè)值是(is)或者不是(!is)一個(gè)特定類型的值赦政。注意: 由于智能轉(zhuǎn)換胜宇,你可以訪問該類型的方法和屬性而無需 任何額外的檢測(cè)。
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
when 也可以用來取代 if-else if鏈。 如果不提供參數(shù)桐愉,所有的分支條件都是簡(jiǎn)單的布爾表達(dá)式封寞,而當(dāng)一個(gè)分支的條件為真時(shí)則執(zhí)行該分支:
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
For 循環(huán)
1 for (item in collection)
2 for (item: Int in ints)
3 for (i in array.indices) {
print(array[i])
}
4 for ((index, value) in array.withIndex()) {
println("the element at value")
}
while 與 do...while 循環(huán)
var x = 5
while (x > 0) {
println( x--)
}
println("----do...while 使用-----")
var y = 5
do {
println(y--)
} while(y>0)
return。默認(rèn)從最直接包圍它的函數(shù)或者匿名函數(shù)返回仅财。
break狈究。終止最直接包圍它的循環(huán)。
continue盏求。繼續(xù)下一次最直接包圍它的循環(huán)抖锥。
Break 和 Continue 標(biāo)簽
在 Kotlin 中任何表達(dá)式都可以用標(biāo)簽(label)來標(biāo)記。 標(biāo)簽的格式為標(biāo)識(shí)符后跟 @ 符號(hào)碎罚,例如:abc@磅废、fooBar@都是有效的標(biāo)簽。 要為一個(gè)表達(dá)式加標(biāo)簽荆烈,我們只要在其前加標(biāo)簽即可拯勉。
//下面的代碼是執(zhí)行一遍,后面就不執(zhí)行了
loop@ for (i in 1..100) {
for (j in 1..100) {
if (j==2) break@loop
println("數(shù)字"+j)
}
}
標(biāo)簽限制的 break 跳轉(zhuǎn)到剛好位于該標(biāo)簽指定的循環(huán)后面的執(zhí)行點(diǎn)憔购。 continue 繼續(xù)標(biāo)簽指定的循環(huán)的下一次迭代宫峦。
標(biāo)簽處返回
Kotlin 有函數(shù)字面量、局部函數(shù)和對(duì)象表達(dá)式玫鸟。因此 Kotlin 的函數(shù)可以被嵌套导绷。 標(biāo)簽限制的 return 允許我們從外層函數(shù)返回。 最重要的一個(gè)用途就是從 lambda 表達(dá)式中返回屎飘⊥浊回想一下我們這么寫的時(shí)候:
fun foo() {
ints.forEach {
if (it == 0) return
print(it)
}
}
這個(gè) return 表達(dá)式從最直接包圍它的函數(shù)即 foo 中返回。 (注意钦购,這種非局部的返回只支持傳給內(nèi)聯(lián)函數(shù)的 lambda 表達(dá)式檐盟。) 如果我們需要從 lambda 表達(dá)式中返回,我們必須給它加標(biāo)簽并用以限制 return押桃。
fun foo() {
ints.forEach lit@ {
if (it == 0) return@lit
print(it)
}
}
現(xiàn)在葵萎,它只會(huì)從 lambda 表達(dá)式中返回。通常情況下使用隱式標(biāo)簽更方便怨规。 該標(biāo)簽與接受該 lambda 的函數(shù)同名陌宿。
fun foo() {
ints.forEach {
if (it == 0) return@forEach
print(it)
}
}
或者锡足,我們用一個(gè)匿名函數(shù)替代 lambda 表達(dá)式波丰。 匿名函數(shù)內(nèi)部的 return 語(yǔ)句將從該匿名函數(shù)自身返回
fun foo() {
ints.forEach(fun(value: Int) {
if (value == 0) return
print(value)
})
}
當(dāng)要返一個(gè)回值的時(shí)候,解析器優(yōu)先選用標(biāo)簽限制的 return舶得,即
return@a 1
意為"從標(biāo)簽 @a 返回 1"掰烟,而不是"返回一個(gè)標(biāo)簽標(biāo)注的表達(dá)式 (@a 1)"。
Kotlin 類和對(duì)象
Kotlin 類可以包含:構(gòu)造函數(shù)和初始化代碼塊、函數(shù)纫骑、屬性蝎亚、內(nèi)部類、對(duì)象聲明先馆。
class Runoob { // 類名為 Runoob
// 大括號(hào)內(nèi)是類體構(gòu)成
}
class Empty 空類
class Runoob() {
fun foo() { print("Foo") } // 成員函數(shù)
}
類的屬性可以用關(guān)鍵字 var 聲明為可變的发框,否則使用只讀關(guān)鍵字 val 聲明為不可變。
class Runoob {
var name: String = ……
var url: String = ……
var city: String = ……
}
我們可以像使用普通函數(shù)那樣使用構(gòu)造函數(shù)創(chuàng)建類實(shí)例:
val site = Runoob() // Kotlin 中沒有 new 關(guān)鍵字
要使用一個(gè)屬性煤墙,只要用名稱引用它即可
site.name // 使用 . 號(hào)來引用
site.url
Koltin 中的類可以有一個(gè) 主構(gòu)造器梅惯,以及一個(gè)或多個(gè)次構(gòu)造器,主構(gòu)造器是類頭部的一部分仿野,位于類名稱之后:
class Person constructor(firstName: String) {}
如果主構(gòu)造器沒有任何注解铣减,也沒有任何可見度修飾符,那么constructor關(guān)鍵字可以省略脚作。
class Person(firstName: String) {
}
如果屬性類型可以從初始化語(yǔ)句或者類的成員函數(shù)中推斷出來葫哗,那就可以省去類型,val不允許設(shè)置setter函數(shù)球涛,因?yàn)樗侵蛔x的劣针。
var allByDefault: Int? // 錯(cuò)誤: 需要一個(gè)初始化語(yǔ)句, 默認(rèn)實(shí)現(xiàn)了 getter 和 setter 方法
var initialized = 1 // 類型為 Int, 默認(rèn)實(shí)現(xiàn)了 getter 和 setter
val simple: Int? // 類型為 Int ,默認(rèn)實(shí)現(xiàn) getter 亿扁,但必須在構(gòu)造函數(shù)中初始化
val inferredType = 1 // 類型為 Int 類型,默認(rèn)實(shí)現(xiàn) getter
實(shí)例
class Person {
lateinit var subject: String
var lastName: String = "zhang"
get() = field.toUpperCase() // 將變量賦值后轉(zhuǎn)換為大寫
set
var no: Int = 100
get() = field // 后端變量
set(value) {
if (value < 10) { // 如果傳入的值小于 10 返回該值
field = value
} else {
field = -1 // 如果傳入的值大于等于 10 返回 -1
}
}
var heiht: Float = 145.4f
private set
}
// 測(cè)試
fun main(args: Array<String>) {
var person: Person = Person()
person.lastName = "wang"
println("lastName:${person.lastName}")
person.no = 9
println("no:${person.no}")
person.no = 20
println("no:${person.no}")
}
Kotlin 中類不能有字段酿秸。提供了 Backing Fields(后端變量) 機(jī)制,備用字段使用field關(guān)鍵字聲明,field 關(guān)鍵詞只能用于屬性的訪問器
非空屬性必須在定義的時(shí)候初始化,kotlin提供了一種可以延遲初始化的方案,使用 lateinit 關(guān)鍵字描述屬性
Kotlin 中,任何時(shí)候當(dāng)你寫出“一個(gè)變量后邊加等于號(hào)”這種形式的時(shí)候魏烫,比如我們定義 var no: Int 變量辣苏,當(dāng)你寫出 no = ... 這種形式的時(shí)候,這個(gè)等于號(hào)都會(huì)被編譯器翻譯成調(diào)用 setter 方法哄褒;而同樣稀蟋,在任何位置引用變量時(shí),只要出現(xiàn) no 變量的地方都會(huì)被編譯器翻譯成 getter 方法呐赡。那么問題就來了退客,當(dāng)你在 setter 方法內(nèi)部寫出 no = ... 時(shí),相當(dāng)于在 setter 方法中調(diào)用 setter 方法链嘀,形成遞歸萌狂,進(jìn)而形成死循環(huán)
主構(gòu)造器中不能包含任何代碼,初始化代碼可以放在初始化代碼段中怀泊,初始化代碼段使用 init 關(guān)鍵字作為前綴茫藏。
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
如果構(gòu)造器有注解,或者有可見度修飾符霹琼,這時(shí)constructor關(guān)鍵字是必須的务傲,注解和修飾符要放在它之前凉当。
次構(gòu)造函數(shù)
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
如果類有主構(gòu)造函數(shù),每個(gè)次構(gòu)造函數(shù)都要售葡,或直接或間接通過另一個(gè)次構(gòu)造函數(shù)代理主構(gòu)造函數(shù)看杭。在同一個(gè)類中代理另一個(gè)構(gòu)造函數(shù)使用 this 關(guān)鍵字:
class Person(val name: String) {
constructor (name: String, age:Int) : this(name) {
// 初始化...
}
}
如果一個(gè)非抽象類沒有聲明構(gòu)造函數(shù)(主構(gòu)造函數(shù)或次構(gòu)造函數(shù)),它會(huì)產(chǎn)生一個(gè)沒有參數(shù)的構(gòu)造函數(shù)挟伙。構(gòu)造函數(shù)是 public 楼雹。如果你不想你的類有公共的構(gòu)造函數(shù),你就得聲明一個(gè)空的主構(gòu)造函數(shù):
class DontCreateMe private constructor () {
}
注意:在 JVM 虛擬機(jī)中尖阔,如果主構(gòu)造函數(shù)的所有參數(shù)都有默認(rèn)值烘豹,編譯器會(huì)生成一個(gè)附加的無參的構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)會(huì)直接使用默認(rèn)值诺祸。這使得 Kotlin 可以更簡(jiǎn)單的使用像 Jackson 或者 JPA 這樣使用無參構(gòu)造函數(shù)來創(chuàng)建類實(shí)例的庫(kù)携悯。
class Customer(val customerName: String = "")
抽象類
抽象是面向?qū)ο缶幊痰奶卣髦唬惐旧砜瓯浚蝾愔械牟糠殖蓡T憔鬼,都可以聲明為abstract的。抽象成員在類中不存在具體的實(shí)現(xiàn)胃夏。
注意:無需對(duì)抽象類或抽象成員標(biāo)注open注解轴或。
open class Base{
open fun f(){}
}
abstract class Derivied:Base(){
override abstract fun f()
}
abstract class NN{
abstract fun f()
}
abstract class MM:NN(){
}
class MN:MM(){
override fun f() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
嵌套類
class Outer { // 外部類
private val bar: Int = 1
class Nested { // 嵌套類
fun foo() = 2
}
}
fun main(args: Array<String>) {
val demo = Outer.Nested().foo() // 調(diào)用格式:外部類.嵌套類.嵌套類方法/屬性
println(demo) // == 2
}
內(nèi)部類
內(nèi)部類使用 inner 關(guān)鍵字來表示。
內(nèi)部類會(huì)帶有一個(gè)對(duì)外部類的對(duì)象的引用仰禀,所以內(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)
}
}
}
fun main(args: Array<String>) {
val demo = Outer().Inner().foo()
println(demo) // 1
val demo2 = Outer().Inner().innerTest()
println(demo2) // 內(nèi)部類可以引用外部類的成員答恶,例如:成員屬性
}
為了消除歧義饺蚊,要訪問來自外部作用域的 this,我們使用this@label悬嗓,其中 @label 是一個(gè) 代指 this 來源的標(biāo)簽污呼。
匿名內(nèi)部類
class Test {
var v = "成員屬性"
fun setInterFace(test: TestInterFace) {
test.test()
}
}
/**
* 定義接口
*/
interface TestInterFace {
fun test()
}
fun main(args: Array<String>) {
var test = Test()
/**
* 采用對(duì)象表達(dá)式來創(chuàng)建接口對(duì)象,即匿名內(nèi)部類的實(shí)例包竹。
*/
test.setInterFace(object : TestInterFace { //object是不能改變的
override fun test() {
println("對(duì)象表達(dá)式創(chuàng)建匿名內(nèi)部類的實(shí)例")
}
})
}
嵌套類和內(nèi)部類在使用時(shí)的區(qū)別
(1)創(chuàng)建對(duì)象的區(qū)別
var demo = Outter.Nested()// 嵌套類燕酷,Outter后邊沒有括號(hào)
var demo = Outter().Inner();// 內(nèi)部類,Outter后邊有括號(hào)
也就是說周瞎,要想構(gòu)造內(nèi)部類的對(duì)象苗缩,必須先構(gòu)造外部類的對(duì)象,而嵌套類則不需要声诸;
(2)引用外部類的成員變量的方式不同
嵌套類
class Outer { // 外部類
private val bar: Int = 1
class Nested { // 嵌套類
var ot: Outer = Outer()
println(ot.bar) // 嵌套類可以引用外部類私有變量酱讶,但要先創(chuàng)建外部類的實(shí)例,不能直接引用
fun foo() = 2
}
}
類的修飾符
類的修飾符包括 classModifier 和accessModifier:
1.classModifier: 類屬性修飾符双絮,標(biāo)示類本身特性浴麻。
abstract // 抽象類
final // 類不可繼承,默認(rèn)屬性
enum // 枚舉類
open // 類可繼承囤攀,類默認(rèn)是final的
annotation // 注解類
2.accessModifier: 訪問權(quán)限修飾符
private // 僅在同一個(gè)文件中可見
protected // 同一個(gè)文件中或子類可見
public // 所有調(diào)用的地方都可見
internal // 同一個(gè)模塊中可見
Kotlin 繼承
Kotlin 中所有類都繼承該 Any 類软免,它是所有類的超類,對(duì)于沒有超類型聲明的類是默認(rèn)超類:
class Example // 從 Any 隱式繼承
Any 默認(rèn)提供了三個(gè)函數(shù):
equals()
hashCode()
toString()
注意:Any 不是 java.lang.Object焚挠。
如果一個(gè)類要被繼承膏萧,可以使用 open 關(guān)鍵字進(jìn)行修飾。
open class Base(p: Int) // 定義基類
class Derived(p: Int) : Base(p)
構(gòu)造函數(shù)
子類有主構(gòu)造函數(shù)
如果子類有主構(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ù),則必須在每一個(gè)二級(jí)構(gòu)造函數(shù)中用 super 關(guān)鍵字初始化基類噩斟,或者在代理另一個(gè)構(gòu)造函數(shù)曹锨。初始化基類時(shí),可以調(diào)用基類的不同構(gòu)造方法剃允。
class Student : Person {
constructor(ctx: Context) : super(ctx) {
}
constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
}
}
open class Person(name:String){
/**次級(jí)構(gòu)造函數(shù)**/
constructor(name:String,age:Int):this(name){
//初始化
println("-------基類次級(jí)構(gòu)造函數(shù)---------")
}
}
重寫
在基類中沛简,使用fun聲明函數(shù)時(shí),此函數(shù)默認(rèn)為final修飾斥废,不能被子類重寫椒楣。如果允許子類重寫該函數(shù),那么就要手動(dòng)添加 open 修飾它, 子類重寫方法使用 override 關(guān)鍵詞
open class A {
open fun f () { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") } //接口的成員變量默認(rèn)是 open 的
fun b() { print("b") }
}
class C() : A() , B{
override fun f() {
super<A>.f()//調(diào)用 A.f()
super<B>.f()//調(diào)用 B.f()
}
}
fun main(args: Array<String>) {
val c = C()
c.f();
}
C 繼承自 a() 或 b(), C 不僅可以從 A 或則 B 中繼承函數(shù)牡肉,而且 C 可以繼承 A()捧灰、B() 中共有的函數(shù)。此時(shí)該函數(shù)在中只有一個(gè)實(shí)現(xiàn)统锤,為了消除歧義毛俏,該函數(shù)必須調(diào)用A()和B()中該函數(shù)的實(shí)現(xiàn),并提供自己的實(shí)現(xiàn)饲窿。
屬性重寫使用 override 關(guān)鍵字拧抖,屬性必須具有兼容類型,每一個(gè)聲明的屬性都可以通過初始化程序或者getter方法被重寫:
open class Foo {
open val x: Int get { …… }
}
class Bar1 : Foo() {
override val x: Int = ……
}
你可以用一個(gè)var屬性重寫一個(gè)val屬性免绿,但是反過來不行唧席。因?yàn)関al屬性本身定義了getter方法,重寫為var屬性會(huì)在衍生類中額外聲明一個(gè)setter方法
interface Foo {
val count: Int
}
class Bar1(override val count: Int) : Foo
class Bar2 : Foo {
override var count: Int = 0
}
子類繼承父類時(shí)嘲驾,不能有跟父類同名的變量淌哟,除非父類中該變量為 private,或者父類中該變量為 open 并且子類用 override 關(guān)鍵字重寫
子類中的 val 不能有 setter 方法辽故,所以無法“覆蓋”父類中 var 的 setter 方法徒仓,相當(dāng)于縮小了父類中相應(yīng)屬性的使用范圍,是不允許的誊垢,就像我們不能把父類中一個(gè) public 方法重寫成 private 方法一樣掉弛。