2019-03-07

函數(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

字符串模板

表示一個(gè)變量名或者變量值varName 表示變量值
${varName.fun()} 表示變量的方法返回值

var a = 1
// 模板中的簡(jiǎn)單名稱:
val s1 = "a is a" a = 2 // 模板中的任意表達(dá)式: 花括號(hào)擴(kuò)起來的任意表達(dá)式 val s2 = "{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ù)字類型,\color{red}{你每定義的一個(gè)變量,其實(shí) Kotlin 幫你封裝了一個(gè)對(duì)象},這樣可以保證不會(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 index isvalue")
}

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 方法一樣掉弛。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末症见,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子殃饿,更是在濱河造成了極大的恐慌谋作,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乎芳,死亡現(xiàn)場(chǎng)離奇詭異遵蚜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)奈惑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門吭净,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肴甸,你說我怎么就攤上這事寂殉。” “怎么了原在?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵不撑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我晤斩,道長(zhǎng)焕檬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任澳泵,我火速辦了婚禮实愚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘兔辅。我一直安慰自己腊敲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布维苔。 她就那樣靜靜地躺著碰辅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪介时。 梳的紋絲不亂的頭發(fā)上没宾,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音沸柔,去河邊找鬼循衰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛褐澎,可吹牛的內(nèi)容都是我干的会钝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼工三,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼迁酸!你這毒婦竟也來了先鱼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤奸鬓,失蹤者是張志新(化名)和其女友劉穎焙畔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體全蝶,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闹蒜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年寺枉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抑淫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡姥闪,死狀恐怖始苇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情筐喳,我是刑警寧澤催式,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站避归,受9級(jí)特大地震影響荣月,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梳毙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一哺窄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧账锹,春花似錦萌业、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至廓奕,卻和暖如春抱婉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背桌粉。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工授段, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人番甩。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓侵贵,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親缘薛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窍育,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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