前言
本文章只是用于記錄學(xué)習(xí)筷厘,所以部分地方如果有錯(cuò)誤或者理解不對(duì)的地方,麻煩請(qǐng)指正宏所。本篇為 csdn 原文章 轉(zhuǎn)移修改版 原文章
簡述:
- kotlin 中接口的簡單使用
- kotlin 中 類和屬性的繼承
- kotlin 中類的重載函數(shù)
- kotlin 中修飾符的介紹
- kotlin 中嵌套類 內(nèi)部類的講解
- kotlin 的主構(gòu)造函數(shù)和次構(gòu)造函數(shù)
1.接口
相比于 java 的接口酥艳,kotlin 還是有點(diǎn)不同的
1.Kotlin 的接口聲明 默認(rèn)都是 final 和 public 的
2.Kotlin 中的接口 和 java 1.8 接口相似,可以包含 抽象方法的定義 和 非抽象方法的實(shí)現(xiàn)
// 接口
interface Clicker{
fun click()
}
// 實(shí)現(xiàn)類
class MeButton : Clicker{
override fun click() {
println("not implemented")
}
}
// 調(diào)用
fun main(args: Array<String>) {
var button:MeButton = MeButton()
button.click()
}
?? 上述代碼爬骤,我們看到 kotlin 中 使用 “:” 代替了 java 中的 extends 和 implements , 和 java 相同的充石,kotlin 也是單繼承,但是可以實(shí)現(xiàn)多個(gè)接口霞玄。和java 中的 @override 相同骤铃,override 用來注釋 繼承父類的方法,或者 接口的方法或?qū)傩钥谰纾煌氖?kotlin 中的 override 是強(qiáng)制添加上的惰爬,這樣可以避免先寫實(shí)現(xiàn)方法 在添加抽象方法 造成的重寫。
kotlin 接口中可以有默認(rèn)實(shí)現(xiàn)的方法惫企,但是java 中則需要在方法中表明 default 關(guān)鍵字撕瞧,而kotlin中是不用添加 關(guān)鍵字的。
interface Clicker{
fun click()
fun staticClick(){
println("默認(rèn)實(shí)現(xiàn)")
}
}
?? 如果你 實(shí)現(xiàn)了這個(gè)接口狞尔,你也可以繼承該方法丛版,對(duì)他進(jìn)行修改,當(dāng)然你也可以不實(shí)現(xiàn)該方法偏序。
1.如果 你分別繼承兩個(gè) 接口硼婿,兩個(gè)接口有相同的默認(rèn)實(shí)現(xiàn)函數(shù),如果不顯式的指明調(diào)用哪一個(gè)禽车,運(yùn)行的時(shí)候會(huì)報(bào)錯(cuò)寇漫。
2.解決辦法就是 實(shí)現(xiàn)兩個(gè)接口中相同名稱的函數(shù),在函數(shù)中指明引用殉摔,
2.1 super< AInterface >.click(); super< BInterface >.click(); 而在java中的表達(dá)方式則是 AInterface .super.click(); 表現(xiàn)方式不太一樣
2. 繼承
?2.1 繼承函數(shù)
??java 中的父類默認(rèn)都是 可以繼承的州胳,所以我們?cè)趯?BaseActivity 或者 BaseFragment 的時(shí)候都要慎重的設(shè)計(jì),因?yàn)橐徊恍⌒?就會(huì)讓子類實(shí)現(xiàn)很多沒有的類逸月。所以 kotlin中 的方法默認(rèn)都是 final 栓撞,如果需要子類繼承就要特地標(biāo)記 open 修飾符。
class MeButton : Clicker{
override fun click() { // 實(shí)現(xiàn) Clicker 方法 默認(rèn) 為open 可繼承
println("not implemented")
}
fun dieable(){} // 默認(rèn)為 final
open fun openClass(){} // 明確表明 為open 可繼承
}
?? 如果是實(shí)現(xiàn) 基類的方法 或者 接口的方法,默認(rèn)是open 的瓤湘,如果希望改變瓢颅,可以自己添加修飾符 final 。
Kotlin 中所有類都有一個(gè)共同的超類 Any弛说,這對(duì)于沒有超類型聲明的類是默認(rèn)超類
?2.2 繼承屬性
?? 繼承屬性和繼承函數(shù)差不多挽懦,在父類中聲明然后在子類中重新聲明的屬性必須以 override 開頭,并且它們必須具有兼容的類型木人。每個(gè)聲明的屬性可以由具有初始化器的屬性或者具有 getter 方法的屬性覆蓋信柿。
?? 注意: var 屬性可以繼承自一個(gè) val 屬性 ,反之則不可以醒第。(var 屬性不能 讓val 繼承 )
interface Foo {
val count: Int
}
class Bar1(override val count: Int) : Foo
class Bar2 : Foo {
override var count: Int = 0
}
?? 上述代碼渔嚷,我們?cè)谥鳂?gòu)造函數(shù)中也可以使用 override 。
?2.3 abstract
我們通過一段代碼 來了解一下 abstract
// 抽象類稠曼,不能創(chuàng)建實(shí)例
abstract class abClas{
// 抽象方法 默認(rèn)就是open(此處省略) 不能實(shí)例形病,必須繼承實(shí)現(xiàn)
abstract fun ab1()
//抽象類中的 方法 不是默認(rèn)open的,所以需要標(biāo)明
open fun ab2(){}
fun ab3(){}
}
其他地方和 java 的都比較相似霞幅,這里就不多贅述
2.4 重載函數(shù)
由于在Java中是沒有默認(rèn)值參數(shù)的概念窒朋,當(dāng)我們需要從Java中調(diào)用Kotlin中的默認(rèn)值重載函數(shù)的時(shí)候,必須顯示的指定所有參數(shù)值蝗岖。但是這個(gè)絕對(duì)不是我們想要侥猩,否則Kotlin就失去了重載的意義了不能和Java完全互操作。所以在Kotlin給出了另一個(gè)方案就是使用@JvmOverloads注解這樣就會(huì)自動(dòng)生成多個(gè)重載方法供Java調(diào)用抵赢。
@JvmOverloads
fun <T> joinString(
collection: Collection<T> = listOf(),
separator: String = ",",
prefix: String = "",
postfix: String = ""
): String {
return collection.joinToString(separator, prefix, postfix)
}
//調(diào)用的地方
fun main(args: Array<String>) {
//函數(shù)使用命名參數(shù)可以提高代碼可讀性
println(joinString(collection = listOf(1, 2, 3, 4), separator = "%", prefix = "<", postfix = ">"))
println(joinString(collection = listOf(1, 2, 3, 4), separator = "%", prefix = "<", postfix = ">"))
println(joinString(collection = listOf(1, 2, 3, 4), prefix = "<", postfix = ">"))
println(joinString(collection = listOf(1, 2, 3, 4), separator = "!", prefix = "<"))
println(joinString(collection = listOf(1, 2, 3, 4), separator = "!", postfix = ">"))
println(joinString(collection = listOf(1, 2, 3, 4), separator = "!"))
println(joinString(collection = listOf(1, 2, 3, 4), prefix = "<"))
println(joinString(collection = listOf(1, 2, 3, 4), postfix = ">"))
println(joinString(collection = listOf(1, 2, 3, 4)))
}
3. 修飾符
??和 java 的大多數(shù)修飾符是一樣的欺劳,但是java 默認(rèn)為 private ,但是kotlin 中默認(rèn)為 public 铅鲤,并且 kotlin中沒有 包可見划提,新添加的修飾符為 :internal ,表示只在模塊內(nèi)部可用。
1.在kotlin 中 public 是不可以訪問 低可見性 internal 的邢享。
2.另外還要注意的是 protected 鹏往,在java 中他的訪問范圍是 包中,但是在kotlin 中則是 局限到 類 或者子類中骇塘,
- 類的擴(kuò)展函數(shù) 是訪問不到 private 和 protected 的伊履。
4. 嵌套類 內(nèi)部類
??和java 一樣,kotlin 也是可以在類中 包 類款违,但是 內(nèi)部類是不可以訪問 外部類的屬性的 唐瀑,除非你做 了特殊的 安排。
class MeButton : Clicker {
private var a: Int = 1
override fun click() {
println("not implemented")
}
fun dieable() {}
open fun openClass() {}
// inner 關(guān)鍵字是重點(diǎn)
inner class CButton {
var b: Int = a
}
}
??從上述代碼中看到插爹,我這里在 類 MeButton 中新添加了一個(gè) 類 CButton 哄辣,如果在沒有添加 inner 的情況下请梢,稱之為 嵌套類,CButton 中是無法獲取到外部類的引用的力穗。
??如果添加上 inner 后毅弧,則算是內(nèi)部類,可以獲取到外部類的引用当窗。
5. 類
??類 不管是 在 java 和 kotlin 中都是比較重要的一部分够坐,前邊的幾張我們也都寫了很多 class 的代碼 ,這里我們?cè)敿?xì)的講解下超全。
// Kotlin 中使用關(guān)鍵字 class 聲明類
class Invoice { ... }
class Empty
?? 類聲明由類名咆霜、類頭 以及由花括號(hào)包圍的類體構(gòu)成邓馒。類頭與類體都是可選的嘶朱; 如果一個(gè)類沒有類體,可以省略花括號(hào)光酣。
?5.1 主構(gòu)造函數(shù)
??Kotlin 中的一個(gè)類可以有一個(gè)主構(gòu)造函數(shù)以及一個(gè)或多個(gè)次構(gòu)造函數(shù)疏遏。主構(gòu)造函數(shù)是類頭的一部分:它跟在類名后。
class Person constructor(firstName: String) { }
class Person (firstName: String) { }
?上述代碼 就是典型的 構(gòu)造函數(shù)救军,我們可以使用 constructor 關(guān)鍵字來形容财异,當(dāng)然如果該類沒有其他修飾符 可以省略 constructor 不寫。
?5.2 初始化 init
初始化的代碼可以放到以 init 關(guān)鍵字作為前綴的初始化塊中唱遭。
初始化代碼塊
class InitOrderDemo(name: String) {
val secondProperty = "Second property: ${name.length}".also(::println)
val customerKey = name.toUpperCase()
val firstProperty = "First property: $name".also(::println)
init {
println("First initializer block that prints ${name}")
}
init {
println("Second initializer block that prints ${name.length}")
}
}
// 運(yùn)行代碼
fun main(args: Array<String>) {
InitOrderDemo("hello")
}
運(yùn)行結(jié)果
Second property: 5
First property: hello
First initializer block that prints hello
Second initializer block that prints 5
??上段代碼我們初步了解了 init 的使用方法戳寸, 主構(gòu)造的參數(shù)可以在初始化塊中使用 或者是 屬性中(val customerKey = name.toUpperCase())。
如果構(gòu)造函數(shù)有注解或可見性修飾符拷泽,這個(gè) constructor 關(guān)鍵字是必需的疫鹊,并且這些修飾符在它前面:
public class Customer @Inject constructor(name: String) { }
?5.3 次構(gòu)造函數(shù)
類也可以聲明前綴有 constructor的次構(gòu)造函數(shù):
class Person {
// 次 構(gòu)造函數(shù)
constructor(parent: Person) {
parent.children.add(this)
}
}
??如果類有一個(gè)主構(gòu)造函數(shù),每個(gè)次構(gòu)造函數(shù)需要委托給主構(gòu)造函數(shù)司致, 可以直接委托或者通過別的次構(gòu)造函數(shù)間接委托拆吆。委托到同一個(gè)類的另一個(gè)構(gòu)造函數(shù)用 this 關(guān)鍵字即可:
??初始化塊 init 中的代碼實(shí)際上會(huì)成為主構(gòu)造函數(shù)的一部分。委托給主構(gòu)造函數(shù)會(huì)作為次構(gòu)造函數(shù)的第一條語句脂矫,因此所有初始化塊中的代碼都會(huì)在次構(gòu)造函數(shù)體之前執(zhí)行枣耀。即使該類沒有主構(gòu)造函數(shù),這種委托仍會(huì)隱式發(fā)生庭再,并且仍會(huì)執(zhí)行初始化塊
??如果一個(gè) 非 抽象類 沒有聲明 任何 構(gòu)造函數(shù)捞奕,那么 程序會(huì)默認(rèn)生成一個(gè)沒有參數(shù) 可見性為 public 的主構(gòu)造函數(shù),如果你不希望你的類有一個(gè)公有構(gòu)造函數(shù)拄轻,你需要聲明一個(gè)帶有非默認(rèn)可見性的空的主構(gòu)造函數(shù)缝彬。