對象表達式(Object expression),對象聲明,伴生對象(companion object)詳解
對象表達式(Object expression)
Java當中匿名內部類在很多場景下大量使用。Kotlin的對象表達式就是爲了解決匿名內部類的一些缺陷而產生的。
- 匿名內部類是沒有名字的類
- 匿名內部類一定是繼承了某個父類,或是實現了某個接口
- Java運行時將該匿名內部類當做它所實現的接口或是所繼承的父類看待。
對象表達式的格式: Object[: 若干個父類型,中間用逗號分隔]
interface MyInterface{
fun myPrint(i:Int)
}
abstract class MyAbstractClass{
abstract val age:Int
abstract fun printMyAbstractInfo()
}
fun main(args: Array<String>) {
var myObject=object :MyInterface{
override fun myPrint(i: Int) {
println("i的值是$i")
}
}
myObject.myPrint(100)
println("-------------")
var myObject2=object {
init {
println("初始化完成")
}
var myProperty="Hello world"
fun myMethod()="myMethod()"
}
println(myObject2.myProperty)
println(myObject2.myMethod())
println("-------------")
var myObject3=object:MyInterface,MyAbstractClass() {
override fun myPrint(i: Int) {
println("i的值$i")
}
override val age: Int
get() = 30
override fun printMyAbstractInfo() {
println("printMyAbstractInfo")
}
}
myObject3.myPrint(50)
println(myObject3.age)
myObject3.printMyAbstractInfo()
}
注意:
匿名對象只能在局部變量範圍內或是被private修飾的成員變量範圍內才能被識別出真正的類型。如果將匿名對象當做一個public方法返回的類型或是public屬性的類型,那麼該方法或是屬性的真正類型,就是該匿名對象所聲明的父類型,如果沒有聲明任何父類型,那麼其類型就是Any,在這種情況下匿名對象中聲明的任何成員都是無法訪問的。如下例子:
class MyClass {
var i:Int=0
private var myobject=object{ //此處的private是非常重要的,不能去掉否則訪問不到output方法
fun output()= println("output invoked")
fun addNumber()=i++ //Kotlin對象表達式中的代碼可以訪問外層的變量,Java外層必須聲明爲final
}
fun myTest(){
println(myobject.javaClass)
myobject.output()
}
}
fun main(args: Array<String>) {
val myClass=MyClass()
myClass.myTest()
}
對象聲明
並且它總是在Object關鍵字後跟一個名稱,對象聲明不是一個表達式,不能用在賦值語句的右邊。對象聲明的初始化過程是線程安全的。
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ……
}
val allDataProviders: Collection<DataProvider>
get() = // ……
}
伴生對象(companion object)
在kotlin中,與java不同的是,類是沒有static方法的。在大多數情況下,Kotlin推薦的做法是使用包級別的函數作爲靜態方法,在Kotlin會將包級別的函數當做靜態方法來提供。 伴生對象默認名字爲Companion.
雖然伴生對象的成員看起來像java中的靜態成員,但在運行期,他們依舊是真實對象的實例成員,在jvm上,可以將伴生對象的成員真正生成爲類的靜態方法與屬性,這是通過@jvmStatic註解來實現的,伴生對象在編譯後會生成一個靜態內部類
class MyTest{
companion object{
var a:Int=20
@JvmStatic //@JvmStatic註解可以將伴生對象的成員真正生成爲類的靜態方法與屬性
fun method(){
println("method invoked!")
}
fun method2(){
println("method2 invoked!")
}
}
}
fun main(args: Array<String>) {
MyTest.method()
println(MyTest.a)
MyTest.method2()
}
對象表達式和對象聲明之間的區別
- 對象表達式是在使用他們的地方立即執行(及初始化)的;
- 對象聲明是在第一次被訪問到時延遲初始化的;
- 伴生對象的初始化是在相應的類被加載(解析)時,與 Java 靜態初始化器的語義相匹配。