????Kotlin的類和接口與Java的類和接口存在較大區(qū)別冗懦,本次主要?dú)w納Kotlin的接口和類如何定義猾漫、繼承以及其一些具體細(xì)節(jié)鲁纠,同時(shí)查看其對(duì)應(yīng)的Java層實(shí)現(xiàn)妖枚。
帶默認(rèn)方法的接口
????Kotlin接口可以包含抽象方法以及非抽象方法的實(shí)現(xiàn)(類似Java 8的默認(rèn)方法)
interface MyInterface {
//抽象方法
fun daqi()
//非抽象方法(即提供默認(rèn)實(shí)現(xiàn)方法)
fun defaultMethod() {
}
}
????接口也可以定義屬性魄衅。聲明的屬性可以是抽象的峭竣,也可以是提供具體訪問器實(shí)現(xiàn)的(即不算抽象的)。
interface MyInterface {
//抽象屬性
var length:Int
//提供訪問器的屬性
val name:String
get() = ""
//抽象方法
fun daqi()
//非抽象方法(即提供默認(rèn)實(shí)現(xiàn)方法)
fun defaultMethod() {
}
}
????接口中聲明的屬性不能有幕后字段晃虫。因?yàn)榻涌谑菬o(wú)狀態(tài)的皆撩,因此接口中聲明的訪問器不能引用它們。(簡(jiǎn)單說就是接口沒有具體的屬性,不能用幕后字段對(duì)屬性進(jìn)行賦值)
接口的實(shí)現(xiàn)
????Kotlin使用 : 替代Java中的extends 和 implements 關(guān)鍵字扛吞。Kotlin和Java一樣呻惕,一個(gè)類可以實(shí)現(xiàn)任意多個(gè)接口,但是只能繼承一個(gè)類滥比。
????接口中抽象的方法和抽象屬性亚脆,實(shí)現(xiàn)接口的類必須對(duì)其提供具體的實(shí)現(xiàn)。
????對(duì)于在接口中提供默認(rèn)實(shí)現(xiàn)的接口方法和提供具體訪問器的屬性盲泛,可以對(duì)其進(jìn)行覆蓋濒持,重新實(shí)現(xiàn)方法和提供新的訪問器實(shí)現(xiàn)。
class MyClass:MyInterface{
//原抽象屬性寺滚,提供具體訪問器
//不提供具體訪問器柑营,提供初始值,使用默認(rèn)訪問器也是沒有問題的
override var length: Int = 0
/*override var length: Int
get() = 0
set(value) {}*/
//覆蓋提供好訪問器的接口屬性
override val name: String
//super.name 其實(shí)是調(diào)用接口中定義的訪問器
get() = super.name
//原抽象方法玛迄,提供具體實(shí)現(xiàn)
override fun daqi() {
}
//覆蓋默認(rèn)方法
override fun defaultMethod() {
super.defaultMethod()
}
}
????無(wú)論是從接口中獲取的屬性還是方法由境,前面都帶有一個(gè)override關(guān)鍵字。該關(guān)鍵字與Java的@Override注解類似蓖议,重寫父類或接口的方法屬性時(shí)虏杰,都 強(qiáng)制 需要用override修飾符進(jìn)行修飾。因?yàn)檫@樣可以避免先寫出實(shí)現(xiàn)方法勒虾,再添加抽象方法造成的意外重寫纺阔。
接口的繼承
????接口也可以從其他接口中派生出來,從而既提供基類成員的實(shí)現(xiàn)修然,也可以聲明新的方法和屬性笛钝。
interface Name {
val name:String
}
interface Person :Name{
fun learn()
}
class daqi:Person{
//為父接口的屬性提供具體的訪問器
override val name: String
get() = "daqi"
//為子接口的方法提供具體的實(shí)現(xiàn)
override fun learn() {
}
}
覆蓋沖突
????在C++中,存在菱形繼承的問題愕宋,即一個(gè)類同時(shí)繼承具有相同函數(shù)簽名的兩個(gè)方法玻靡,到底該選擇哪一個(gè)實(shí)現(xiàn)呢?由于Kotlin的接口支持默認(rèn)方法中贝,當(dāng)一個(gè)類實(shí)現(xiàn)多個(gè)接口囤捻,同時(shí)擁有兩個(gè)具有相同函數(shù)簽名的默認(rèn)方法時(shí),到底選擇哪一個(gè)實(shí)現(xiàn)呢邻寿?
主要根據(jù)以下3條規(guī)則進(jìn)行判斷:
????1蝎土、類中帶override修飾的方法優(yōu)先級(jí)最高。 類或者父類中帶override修飾的方法的優(yōu)先級(jí)高于任何聲明為默認(rèn)方法的優(yōu)先級(jí)绣否。(Kotlin編譯器強(qiáng)制要求誊涯,當(dāng)類中存在和父類或?qū)崿F(xiàn)的接口有相同函數(shù)簽名的方法存在時(shí),需要在前面添加override關(guān)鍵字修飾蒜撮。)
????2暴构、當(dāng)?shù)谝粭l無(wú)法判斷時(shí),子接口的優(yōu)先級(jí)更高。優(yōu)先選擇擁有最具體實(shí)現(xiàn)的默認(rèn)方法的接口丹壕,因?yàn)閺睦^承角度理解庆械,可以認(rèn)為子接口的默認(rèn)方法覆蓋重寫了父接口的默認(rèn)方法,子接口比父接口具體菌赖。
????3缭乘、最后還是無(wú)法判斷時(shí),繼承多個(gè)接口的類需要顯示覆蓋重寫該方法琉用,并選擇調(diào)用期望的默認(rèn)方法堕绩。
- 如何理解第二條規(guī)則?先看看一下例子:
Java繼承自Language邑时,兩者都對(duì)use方法提供了默認(rèn)實(shí)現(xiàn)奴紧。而Java比Language更具體。
interface Language{
fun use() = println("使用語(yǔ)言")
}
interface Java:Language{
override fun use() = println("使用Java語(yǔ)言編程")
}
而實(shí)現(xiàn)這兩個(gè)接口的類中晶丘,并無(wú)覆蓋重寫該方法黍氮,只能選擇更具體的默認(rèn)方法作為其方法實(shí)現(xiàn)。
class Person:Java,Language{
}
//執(zhí)行結(jié)果是輸出:使用Java語(yǔ)言編程
val daqi = Person()
daqi.use()
- 如何理解第三條規(guī)則浅浮?繼續(xù)看例子:
接口Java和Kotlin都提供對(duì)learn方法提供了具體的默認(rèn)實(shí)現(xiàn)沫浆,且兩者并無(wú)明確的繼承關(guān)系。
interface Java {
fun learn() = println("學(xué)習(xí)Java")
}
interface Kotlin{
fun learn() = println("學(xué)習(xí)Kotlin")
}
當(dāng)某類都實(shí)現(xiàn)Java和Kotlin接口時(shí)滚秩,此時(shí)就會(huì)產(chǎn)生覆蓋沖突的問題专执,這個(gè)時(shí)候編譯器會(huì)強(qiáng)制要求你提供自己的實(shí)現(xiàn):
唯一的解決辦法就是顯示覆蓋該方法,如果想沿用接口的默認(rèn)實(shí)現(xiàn)郁油,可以super關(guān)鍵字本股,并將具體的接口名放在super的尖括號(hào)中進(jìn)行調(diào)用。
class Person:Java,Kotlin{
override fun learn() {
super<Java>.learn()
super<Kotlin>.learn()
}
}
對(duì)比Java 8的接口
????Java 8中也一樣可以為接口提供默認(rèn)實(shí)現(xiàn)桐腌,但需要使用default關(guān)鍵字進(jìn)行標(biāo)識(shí)拄显。(Kotlin只需要提供具體的方法實(shí)現(xiàn),即提供函數(shù)體)
public interface Java8 {
default void defaultMethod() {
System.out.println("我是Java8的默認(rèn)方法");
}
}
????面對(duì)覆蓋沖突案站,Java8的和處理和Kotlin的基本相似凿叠,在語(yǔ)法上顯示調(diào)用接口的默認(rèn)方法時(shí)有些不同:
//Java8 顯示調(diào)用覆蓋沖突的方法
Java8.super.defaultMethod()
//Kotlin 顯示調(diào)用覆蓋沖突的方法
super<Kotlin>.learn()
Kotlin 與 Java 間接口的交互
????眾所周知,Java8之前接口沒有默認(rèn)方法嚼吞,Kotlin是如何兼容的呢?定義如下兩個(gè)接口蹬碧,再查看看一下反編譯的結(jié)果:
interface Language{
//默認(rèn)方法
fun use() = println("使用語(yǔ)言編程")
}
interface Java:Language{
//抽象屬性
var className:String
//提供訪問器的屬性
val field:String
get() = ""
//默認(rèn)方法
override fun use() = println("使用Java語(yǔ)言編程")
//抽象方法
fun absMethod()
}
先查看父接口的源碼:
public interface Language {
void use();
public static final class DefaultImpls {
public static void use(Language $this) {
String var1 = "使用語(yǔ)言編程";
System.out.println(var1);
}
}
}
????Language接口中的默認(rèn)方法轉(zhuǎn)換為抽象方法保留在接口中舱禽。其內(nèi)部定義了一個(gè)名為DefaultImpls的靜態(tài)內(nèi)部類,該內(nèi)部類中擁有和默認(rèn)方法相同名稱的靜態(tài)方法恩沽,而該靜態(tài)方法的實(shí)現(xiàn)就是其同名默認(rèn)函數(shù)的具體實(shí)現(xiàn)誊稚。也就是說,Kotlin的默認(rèn)方法轉(zhuǎn)換為靜態(tài)內(nèi)部類DefaultImpls的同名靜態(tài)函數(shù)。
所以里伯,如果想在Java中調(diào)用Kotlin接口的默認(rèn)方法城瞎,需要加多一層DefaultImpls
public class daqiJava implements Language {
@Override
public void use() {
Language.DefaultImpls.use(this);
}
}
再繼續(xù)查看子接口的源碼
public interface Java extends Language {
//抽象屬性的訪問器
@NotNull
String getClassName();
void setClassName(@NotNull String var1);
//提供具體訪問器的屬性
@NotNull
String getField();
//默認(rèn)方法
void use();
//抽象方法
void absMethod();
public static final class DefaultImpls {
@NotNull
public static String getField(Java $this) {
return "";
}
public static void use(Java $this) {
String var1 = "使用Java語(yǔ)言編程";
System.out.println(var1);
}
}
}
????通過源碼觀察到,無(wú)論是抽象屬性還是擁有具體訪問器的屬性疾瓮,都沒有在接口中定義任何屬性脖镀,只是聲明了對(duì)應(yīng)的訪問器方法。(和擴(kuò)展屬性相似)
抽象屬性和提供具體訪問器的屬性區(qū)別是:
- 抽象屬性的訪問器均為抽象方法狼电。
- 擁有具體訪問器的屬性至耻,其訪問器實(shí)現(xiàn)和默認(rèn)方法一樣羽圃,外部聲明一個(gè)同名抽象方法,具體實(shí)現(xiàn)被存儲(chǔ)在靜態(tài)內(nèi)部類DefaultImpls的同名靜態(tài)函數(shù)中。
Java定義的接口,Kotlin繼承后能為其父接口的方法提供默認(rèn)實(shí)現(xiàn)嗎惫皱?當(dāng)然是可以啦:
//Java接口
public interface daqiInterface {
String name = "";
void absMethod();
}
//Kotlin接口
interface daqi: daqiInterface {
override fun absMethod() {
}
}
????Java接口中定義的屬性都是默認(rèn)public static final,對(duì)于Java的靜態(tài)屬性擎淤,在Kotlin中可以像頂層屬性一樣肮砾,直接對(duì)其進(jìn)行使用:
fun main(args: Array<String>) {
println("Java接口中的靜態(tài)屬性name = $name")
}
類
????Kotlin的類可以有一個(gè)主構(gòu)造函數(shù)以及一個(gè)或多個(gè) 從構(gòu)造函數(shù)。主構(gòu)造函數(shù)是類頭的一部分髓抑,即在類體外部聲明咙崎。
主構(gòu)造方法
constructor關(guān)鍵字可以用來聲明 主構(gòu)造方法 或 從構(gòu)造方法。
class Person(val name:String)
//其等價(jià)于
class Person constructor(val name:String)
????主構(gòu)造函數(shù)不能包含任何的代碼启昧。初始化的代碼可以放到以 init 關(guān)鍵字作為前綴的初始化塊中叙凡。
class Person constructor(val name:String){
init {
println("name = $name")
}
}
????構(gòu)造方法的參數(shù)也可以設(shè)置為默認(rèn)參數(shù),當(dāng)所有構(gòu)造方法的參數(shù)都是默認(rèn)參數(shù)時(shí)密末,編譯器會(huì)生成一個(gè)額外的不帶參數(shù)的構(gòu)造方法來使用所有的默認(rèn)值握爷。
class Person constructor(val name:String = "daqi"){
init {
println("name = $name")
}
}
//輸出為:name = daqi
fun main(args: Array<String>) {
Person()
}
????主構(gòu)造方法同時(shí)需要初始化父類,子類可以在其列表參數(shù)中索取父類構(gòu)造方法所需的參數(shù)严里,以便為父類構(gòu)造方法提供參數(shù)新啼。
open class Person constructor(name:String){
}
class daqi(name:String):Person(name){
}
????當(dāng)沒有給一個(gè)類聲明任何構(gòu)造方法,編譯器將生成一個(gè)不做任何事情的默認(rèn)構(gòu)造方法刹碾。對(duì)于只有默認(rèn)構(gòu)造方法的類燥撞,其子類必須顯式地調(diào)用父類的默認(rèn)構(gòu)造方法,即使他沒有參數(shù)迷帜。
open class View
class Button:View()
而接口沒有構(gòu)造方法物舒,所以接口名后不加括號(hào)。
//實(shí)現(xiàn)接口
class Button:ClickListener
當(dāng) 主構(gòu)造方法 有注解或可見性修飾符時(shí)戏锹,constructor 關(guān)鍵字不可忽略冠胯,并且constructor 在這些修飾符和注解的后面。
class Person public @Inject constructor(val name:String)
構(gòu)造方法的可見性是 public锦针,如果想將構(gòu)造方法設(shè)置為私有荠察,可以使用private修飾符置蜀。
class Person private constructor()
從構(gòu)造方法
從構(gòu)造方法使用constructor關(guān)鍵字進(jìn)行聲明
open class View{
//從構(gòu)造方法1
constructor(context:Context){
}
//從構(gòu)造方法2
constructor(context:Context,attr:AttributeSet){
}
}
????使用this關(guān)鍵字,從一個(gè)構(gòu)造方法中調(diào)用該類另一個(gè)構(gòu)造方法悉盆,同時(shí)也能使用super()關(guān)鍵字調(diào)用父類構(gòu)造方法盯荤。
????如果一個(gè)類有 主構(gòu)造方法,每個(gè) 從構(gòu)造方法 都應(yīng)該顯式調(diào)用 主構(gòu)造方法焕盟,否則將其委派給會(huì)調(diào)用主構(gòu)造方法的從構(gòu)造方法秋秤。
class Person constructor(){
//從構(gòu)造方法1,顯式調(diào)用主構(gòu)造方法
constructor(string: String) : this() {
println("從構(gòu)造方法1")
}
//從構(gòu)造方法2京髓,顯式調(diào)用構(gòu)造方法1航缀,間接調(diào)用主構(gòu)造方法。
constructor(data: Int) : this("daqi") {
println("從構(gòu)造方法2")
}
}
注意:
????初始化塊中的代碼實(shí)際上會(huì)成為主構(gòu)造函數(shù)的一部分堰怨。顯式調(diào)用主構(gòu)造方法會(huì)作為次構(gòu)造函數(shù)的第一條語(yǔ)句芥玉,因此所有初始化塊中的代碼都會(huì)在次構(gòu)造函數(shù)體之前執(zhí)行。
即使該類沒有主構(gòu)造函數(shù)备图,這種調(diào)用仍會(huì)隱式發(fā)生灿巧,并且仍會(huì)執(zhí)行初始化塊。
//沒有主構(gòu)造方法的類
class Person{
init {
println("主構(gòu)造方法 init 1")
}
//從構(gòu)造方法默認(rèn)會(huì)執(zhí)行所有初始化塊
constructor(string: String) {
println("從構(gòu)造方法1")
}
init {
println("主構(gòu)造方法 init 2")
}
}
????如果一個(gè)類擁有父類揽涮,但沒有主構(gòu)造方法時(shí)抠藕,每個(gè)從構(gòu)造方法都應(yīng)該初始化父類(即調(diào)用父類的構(gòu)造方法),否則將其委托給會(huì)初始化父類的構(gòu)造方法(即使用this調(diào)用其他會(huì)初始化父類的構(gòu)造方法)蒋困。
class MyButton:View{
//調(diào)用自身的另外一個(gè)從構(gòu)造方法盾似,間接調(diào)用父類的構(gòu)造方法。
constructor(context:Context):this(context,MY_STYLE){
}
//調(diào)用父類的構(gòu)造方法雪标,初始化父類零院。
constructor(context:Context,attr:AttributeSet):super(context,attr){
}
}
脆弱的基類
????Java中允許創(chuàng)建任意類的子類并重寫任意方法,除非顯式地使用final關(guān)鍵字村刨。對(duì)基類進(jìn)行修改導(dǎo)致子類不正確的行為告抄,就是所謂的脆弱的基類。所以Kotlin中類和方法默認(rèn)是final嵌牺,Java類和方法默認(rèn)是open的打洼。
????當(dāng)你允許一個(gè)類存在子類時(shí),需要使用open修飾符修改這個(gè)類逆粹。如果想一個(gè)方法能被子類重寫募疮,也需要使用open修飾符修飾。
open class Person{
//該方法時(shí)final 子類不能對(duì)它進(jìn)行重寫
fun getName(){}
//子類可以對(duì)其進(jìn)行重寫
open fun getAge(){}
}
對(duì)基類或接口的成員進(jìn)行重寫后僻弹,重寫的成員同樣默認(rèn)為open酝锅。(盡管其為override修飾)
如果想改變重寫成員默認(rèn)為open的行為,可以顯式的將重寫成員標(biāo)注為final
open class daqi:Person(){
final override fun getAge() {
super.getAge()
}
}
抽象類的成員和接口的成員始終是open的奢方,不需要顯式地使用open修飾符搔扁。
可見性修飾符
????Kotlin和Java的可見性修飾符相似,同樣可以使用public蟋字、protected和private修飾符稿蹲。但Kotlin默認(rèn)可見性是public,而Java默認(rèn)可見性是包私有鹊奖。
????Kotlin中并沒有包私有這種可見性苛聘,Kotlin提供了一個(gè)新的修飾符:internal,表示“只在模塊內(nèi)部可見”。模塊是指一組一起編譯的Kotlin文件忠聚∩杌可能是一個(gè)Gradle項(xiàng)目,可能是一個(gè)Idea模塊两蟀。internal可見性的優(yōu)勢(shì)在于它提供了對(duì)模塊實(shí)現(xiàn)細(xì)節(jié)的封裝网梢。
????Kotlin允許在頂層聲明中使用private修飾符,其中包括類聲明赂毯,方法聲明和屬性聲明战虏,但這些聲明只能在聲明它們的文件中可見。
注意:
- 覆蓋一個(gè) protected 成員并且沒有顯式指定其可見性党涕,該成員的可見性還是 protected 烦感。
- 與Java不同,Kotlin的外部類(嵌套類)不能看到其內(nèi)部類中的private成員膛堤。
- internal修飾符編譯成字節(jié)碼轉(zhuǎn)Java后手趣,會(huì)變成public。
- private類轉(zhuǎn)換為Java時(shí),會(huì)變成包私有聲明肥荔,因?yàn)镴ava中類不能聲明為private绿渣。
內(nèi)部類和嵌套類
????Kotlin像Java一樣,允許在一個(gè)類中聲明另一個(gè)類次企。但Kotlin的嵌套類默認(rèn)不能訪問外部類的實(shí)例怯晕,和Java的靜態(tài)內(nèi)部類一樣。
????如果想讓Kotlin內(nèi)部類像Java內(nèi)部類一樣缸棵,持有一個(gè)外部類的引用的話舟茶,需要使用inner修飾符。
內(nèi)部類需要外部類引用時(shí)堵第,需要使用 this@外部類名 來獲取吧凉。
class Person{
private val name = "daqi"
inner class MyInner{
fun getPersonInfo(){
println("name = ${this@Person.name}")
}
}
}
object關(guān)鍵字
對(duì)象聲明
????在Java中創(chuàng)建單例往往需要定義一個(gè)private的構(gòu)造方法,并創(chuàng)建一個(gè)靜態(tài)屬性來持有這個(gè)類的單例踏志。
????Kotlin通過對(duì)象聲明將類聲明和類的單一實(shí)例結(jié)合在一起阀捅。對(duì)象聲明在定義的時(shí)候就立即創(chuàng)建,而這個(gè)初始化過程是線程安全的针余。
????對(duì)象聲明中可以包含屬性饲鄙、方法凄诞、初始化語(yǔ)句等,也支持繼承類和實(shí)現(xiàn)接口忍级,唯一不允許的是不能定義構(gòu)造方法(包括主構(gòu)造方法和從構(gòu)造方法)帆谍。
????對(duì)象聲明不能定義在方法和內(nèi)部類中,但可以定義在其他的對(duì)象聲明和非內(nèi)部類(例如:嵌套類)轴咱。如果需要引用該對(duì)象汛蝙,直接使用其名稱即可。
//定義對(duì)象聲明
class Book private constructor(val name:String){
object Factory {
val name = "印書廠"
fun createAppleBooK():Book{
return Book("Apple")
}
fun createAndroidBooK():Book{
return Book("Android")
}
}
}
調(diào)用對(duì)象聲明的屬性和方法:
Book.Factory.name
Book.Factory.createAndroidBooK()
????將對(duì)象聲明反編譯成Java代碼朴肺,其內(nèi)部實(shí)現(xiàn)也是定義一個(gè)private的構(gòu)造方法窖剑,并始終創(chuàng)建一個(gè)名為INSTANCE的靜態(tài)屬性來持有這個(gè)類的單例,而該類的初始化放在靜態(tài)代碼塊中戈稿。
public final class Book {
//....
public Book(String name, DefaultConstructorMarker $constructor_marker) {
this(name);
}
public static final class Factory {
@NotNull
private static final String name = "印書廠";
public static final Book.Factory INSTANCE;
//...
@NotNull
public final Book createAppleBooK() {
return new Book("Apple", (DefaultConstructorMarker)null);
}
@NotNull
public final Book createAndroidBooK() {
return new Book("Android", (DefaultConstructorMarker)null);
}
private Factory() {
}
static {
Book.Factory var0 = new Book.Factory();
INSTANCE = var0;
name = "印書廠";
}
}
}
用Java調(diào)用對(duì)象聲明的方法:
//Java調(diào)用對(duì)象聲明
Book.Factory.INSTANCE.createAndroidBooK();
伴生對(duì)象
????一般情況下西土,使用頂層函數(shù)可以很好的替代Java中的靜態(tài)函數(shù),但頂層函數(shù)無(wú)法訪問類的private成員器瘪。
????當(dāng)需要定義一個(gè)方法翠储,該方法能在沒有類實(shí)例的情況下,調(diào)用該類的內(nèi)部方法橡疼≡可以定義一個(gè)該類的對(duì)象聲明,并在該對(duì)象聲明中定義該方法欣除。類內(nèi)部的對(duì)象聲明可以用 companion 關(guān)鍵字標(biāo)記住拭,這種對(duì)象叫伴生對(duì)象。
????可以直接通過類名來訪問該伴生對(duì)象的方法和屬性历帚,不用再顯式的指明對(duì)象聲明的名稱滔岳,再訪問該對(duì)象聲明對(duì)象的方法和屬性⊥炖危可以像調(diào)用該類的靜態(tài)函數(shù)和屬性一樣谱煤,不需要再關(guān)心對(duì)象聲明的名稱。
//將構(gòu)造方法私有化
class Book private constructor(val name:String){
//伴生對(duì)象的名稱可定義也可以不定義禽拔。
companion object {
//伴生對(duì)象調(diào)用其內(nèi)部私有構(gòu)造方法
fun createAppleBooK():Book{
return Book("Apple")
}
fun createAndroidBooK():Book{
return Book("Android")
}
}
}
調(diào)用伴生對(duì)象的方法:
Book.createAndroidBooK()
????伴生對(duì)象的實(shí)現(xiàn)和對(duì)象聲明類似刘离,定義一個(gè)private的構(gòu)造方法,并始終創(chuàng)建一個(gè)名為Companion的靜態(tài)屬性來持有這個(gè)類的單例睹栖,并直接對(duì)Companion靜態(tài)屬性進(jìn)行初始化硫惕。
public final class Book {
//..
public static final Book.Companion Companion = new Book.Companion((DefaultConstructorMarker)null);
//...
public static final class Companion {
//...
@NotNull
public final Book createAppleBooK() {
return new Book("Apple", (DefaultConstructorMarker)null);
}
@NotNull
public final Book createAndroidBooK() {
return new Book("Android", (DefaultConstructorMarker)null);
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
伴生對(duì)象的擴(kuò)展
????擴(kuò)展方法機(jī)制允許在任何地方定義某類的擴(kuò)展方法,但需要該類的實(shí)例進(jìn)行調(diào)用野来。當(dāng)需要擴(kuò)展一個(gè)通過類自身調(diào)用的方法時(shí)恼除,如果該類擁有伴生對(duì)象,可以通過對(duì)伴生對(duì)象定義擴(kuò)展方法曼氛。
//對(duì)伴生對(duì)象定義擴(kuò)展方法
fun Book.Companion.sellBooks(){
}
當(dāng)對(duì)該擴(kuò)展方法進(jìn)行調(diào)用時(shí)豁辉,可以直接通過類自身進(jìn)行調(diào)用:
Book.sellBooks()
匿名內(nèi)部類
作為android開發(fā)者令野,在設(shè)置監(jiān)聽時(shí),創(chuàng)建匿名對(duì)象的情況再常見不過了秋忙。
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
????object關(guān)鍵字除了能用來聲明單例式對(duì)象外彩掐,還可以聲明匿名對(duì)象。和對(duì)象聲明不同灰追,匿名對(duì)象不是單例,每次都會(huì)創(chuàng)建一個(gè)新的對(duì)象實(shí)例狗超。
mRecyclerView.setOnClickListener(object :View.OnClickListener{
override fun onClick(v: View?) {
}
});
????當(dāng)該匿名類擁有兩個(gè)以上抽象方法時(shí)弹澎,才需要使用object創(chuàng)建匿名類。否則盡量使用lambda表達(dá)式努咐。
mButton.setOnClickListener {
}
參考文獻(xiàn):
- 《Kotlin實(shí)戰(zhàn)》
- Kotlin官網(wǎng)
android Kotlin系列:
Kotlin知識(shí)歸納(一) —— 基礎(chǔ)語(yǔ)法
Kotlin知識(shí)歸納(二) —— 讓函數(shù)更好調(diào)用
Kotlin知識(shí)歸納(三) —— 頂層成員與擴(kuò)展
Kotlin知識(shí)歸納(六) —— 類型系統(tǒng)