kotlin筆記 第八章 (六)物件表示式、物件宣告與伴生物件.md
如果物件是函式式介面(只有一個抽象方法的介面),則可以使用帶介面類字首的Lambda表示式建立物件,如:Runnable
Var r=Runnable{
......(run()方法實現)
}
1、物件表示式
物件表示式成員:初始化塊、屬性、方法、內部類(不能包含巢狀類),不能有構造器
物件表示式相當於Java中的匿名內部類,但功能更強大:
- 物件表示式可以只用指定父型別,也可以有一個或多個父型別
語法格式:
object[:0-N個父型別(父類類、介面)]{
初始化塊
屬性
方法
內部類,不能包含巢狀類
}
- 物件表示式不能是抽象類,系統在建立物件表示式時就會立即建立物件,因此不允許將物件表示式定義為抽象類
- 物件表示式不能定義構造器,但可以有初始化塊
- 物件表示式可以包含內部類,不能包含巢狀類
Kotlin中表達式:
-
表示式在區域性範圍內(函式或者方法中)或者使用private修飾物件表示式,Kotlin編譯器可以識別物件表示式的真實型別;比如: fun main(args:Array){ var obj=object { var name=“leslie” fun test(){
} }
var obj2=object:outputable { var name=“leslie” fun test(){
} override fun output(msg:String){ } }
}
這裡編譯器是可以識別obj變數的型別的,因此也就可以呼叫其變數以及方法,無論是從父類、既可重寫的方法還是自己新增的方法、屬性
-
***(作為成員變數)***非private修飾的物件表示式就和Java中的匿名內部類一樣了,編譯器只會把該物件表示式當成他父類(介面)處理,不能識別器真實型別,如果物件表示式沒有父類,就當成Any類處理,自然物件表示式中新增的屬性、方法就呼叫不到,只能呼叫繼承、重寫的方法、屬性
class Sub{ //1、private修飾的物件表示式 private var obj={ var name:String=“leslie”
override fun test(mas:String){ } } //2、非private internal var obj2=object:Outputable{ var name:String="leslie" override fun test(mas:String){ } } //3、(單表示式函式),物件表示式作為函式返回值 private fun say()=object:Outputable{ var name:String="leslie" override fun test(mas:String){ } }
//4、(單表示式函式),物件表示式作為函式返回值 internal fun say()=object:Outputable{ var name:String=“leslie”
override fun test(mas:String){ } }
} 第一和第三種情況由於能識別變數真實型別呼叫其name屬性(obj.name、say().name)自然沒有問題,而第二種和第四種情況不能識別其真實型別,只能當做父型別處理,編譯期型別即為父型別,由於沒有name屬性,自然報錯;
還有一點就是:java中要求匿名內部類訪問區域性變數時,區域性變數必須final修飾,就是說該區域性變數不能別被修改,而Kotlin中可以修改該區域性變數;
2、物件宣告
其作用就是實現單例模式;
語法
object 物件宣告名稱[:0-N個父型別]{
//定義屬性
//方法
//巢狀類,不能定義內部類(非靜態內部類)
//初始化塊
}
物件宣告和物件表示式語法大體格式都一樣,也有一些區別:
- 物件表示式是一個表示式(可以看做一個物件),可以被賦值給變數,而物件宣告不是表示式,不能用於賦值
- 物件宣告可以包含巢狀類,但不能包含內部類;而物件表示式只能包含內部類而不能包含巢狀類 3.*** 物件宣告不能定義在函式或方法內,但物件表;達式可巢狀在其他物件宣告中或非內部類中***
物件宣告定義位置
-
在kotlin檔案中定義物件宣告:
interface Outputable{ fun output(msg:String) }
abstract class Product(var price:Double){ abstract val name:String abstract fun printInfo() }
object MyObj1:Outputable{ override fun output(msg: String) { Log.d(“TAG”,“重寫從父類繼承到的方法”) }
}
object MyObj2{ init { Log.d(“TAG”,“初始化塊”) } var name=“Kotlin” fun test(){ Log.d(“TAG”,“test方法”) } class Foo
}
呼叫:MyObj1.output(“輸出裝置”)
-
在類體中定義
class ObjectDecl{ object MyObj3{ init { Log.d("TAG","定義在類體中的物件宣告的初始塊") } var name:String="leslie" class Foo fun info(){ Log.d("TAG","定義在類體中的物件宣告的方法") } } }
物件宣告所定義的物件時該類的唯一例項,通過物件宣告的名稱直接訪問該類的唯一例項;
MyObj1.output(“輸出裝置”)
在類中定義物件宣告
伴生物件
在類中定義物件宣告,使用"conpanion"修飾符,這樣物件就變成了伴生物件;
伴生物件作用:就是為外部類提供靜態屬性、靜態方法,彌補kotlin沒有靜態成員的不足(巢狀類可以看做外部類的靜態成員),物件宣告中的方法、屬性就可看做外部類的靜態屬性、靜態方法
- 一個類最多隻能定義一個伴生物件,半身物件就相當於外部類的物件,可以直接通過外部類直接呼叫伴生物件的成員;
- 伴生物件的名稱可以省略,如果省略後,要訪問伴生物件,就通過Companion名稱訪問伴生物件即:外部類.Companion;那伴生物件可以訪問了,訪問伴生物件的方法、屬性也就輕而易舉了,即:外部類.Companion.屬性/方法
語法:
companion object 伴生物件名稱:(0-N)父型別{
//定義屬性
//方法
//巢狀類,不能定義內部類(非靜態內部類)
//初始化塊
}
如:
interface Outputable{
fun output(msg:String)
}
class MyClass{
companion object MyObj3:Outputable {
//伴生物件中屬性相當於外部類靜態成員變數
val name="name屬性值"
//伴生物件中的方法相當於外部類中靜態方法
override fun output(msg: String) {
for (i in 1..6){
println("<h${i}>${msg}</h${i}>")
}
}
}
}
fun main(args:Array<String>){
MyClass.output("leslie")
println(MyClass.name)
}
Kotlin中取消了static修飾符,伴生物件就是Kotlin彌補中沒有靜態成員的不足;從上面的例子可以看出伴生物件中的屬性、方法分別相當於外部類的靜態變數、靜態方法.
注意:這裡Kotlin只是利用伴生模擬java中靜態成員,但伴生物件的屬性、方法依然是伴生物件的例項成員,並不屬於伴生物件所在的外部類;
伴生物件擴充套件方法
如果一個類具有伴生物件,允許為伴生物件擴充套件方法和屬性,而為伴生物件擴充套件方法和屬性,就就相當於為外部類擴充套件靜態變數、靜態方法