前言
本文我們需要了解幾個點。
①object與any的區別?
②private跟非private返回值的區別?
③Kotlin中單例模式怎麼實現?又如何調用?
④伴生對象什麼時候產生?可以如何調用?
⑤對象表達式、聲明對象、伴生對象 初始化的時機?
本節目錄不重要。帶着這些問題就可以了。
作用
Kotlin的對象表達式,再一次簡化了,對某個類做輕微改動時,且不需要去聲明一個新的子類。
對象表達式
通過匿名內部類
與java一樣,或繼承、或實現、或通過構造函數傳值給其參數。
匿名對象只在本地和私有作用域中聲明
範例一
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { /*……*/ }
override fun mouseEntered(e: MouseEvent) { /*……*/ }
})
知識點複習
理解一下Kotlin中,object與any的區別
- any
定義的方法有:toString()、equals()、hashCode() 3個 - Object類
定義的方法有:toString()、equals()、hashCode()、getClass()、clone()、finalize()、notify()、notifyAll()、wait()、wait(long)、wait(long,int) 11個
我們看一段英文解析,或許更加清晰。
Kotlin compiler treats kotlin.Any and java.lang.Object as two different types,
but at runtime they are represented with the same java.lang.Object class.
編譯器認爲Any和Object是不同的類型;但是在運行時,Any和Object表現出來是一樣的。
這也是Kotlin可以和Java互通的一個提現。運行時,我們都一樣的。
解析
- object:MouseAdapter即是new MouseAdapter()
- 如果不需要 super繼承,僅需要一個object怎麼寫呢
private fun foo() = object {
val x: String = "x"
}
把冒號 後面的去掉
範例二
class C {
// 私有函數,所以其返回類型是匿名對象類型
private fun foo() = object {
val x: String = "x"
}
// 公有函數,所以其返回類型是 Any
fun publicFoo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // 沒問題
val x2 = publicFoo().x // 錯誤:未能解析的引用“x”
}
}
注意
留意上述範例中的 註釋部分
- private函數,會返回 匿名對象類型
- 非private函數,返回的是Any類型
對象聲明
Kotlin 使用 object 關鍵字來聲明一個對象
通過對象聲明,可以獲得一個單例單例單例單例 重要的事情說三遍
範例
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ……
}
val allDataProviders: Collection<DataProvider>
get() = // ……
}
這就是對象聲明。
彷彿是你聲明瞭一個變量一樣
如何調用呢?
DataProviderManager.registerDataProvider(……)
單例的調用不用getInstance了。砍砍砍,砍代碼量啊
來看範例一
var data1 = DataProviderManager
var data2 = DataProviderManager
data1.name = "test"
print("data1 name = ${data2.name}")
//這裏data1.name 和data2.name是一樣的
注意
object聲明的單例,只能通過類名來訪問!!!
Kotlin的單例,避免了getInstance,直接調用。
砍砍砍,砍代碼量啊
看個範例二
class Engineer {
var name = "wangxueming"
object Info {
var sex = "man"
fun showName(){
print{"desk legs $name"} // 錯誤,不能訪問到外部類的方法和變量
}
}
}
fun main(args: Array<String>) {
var wxm = Engineer()
wxm.Info.sex // 錯誤,不能通過外部類的實例訪問到該對象
Engineer.Info.sex // 正確
}
通過object聲明的對象,是單例,而且!只能!通過 類名 範文。不得不說,這避免了不少麻煩事。
明擺的事情!我訪問單例,肯定就是那麼個實例。
伴生對象
用 companion 關鍵字標記
與外部類關聯在一起!!!如影隨形
可以直接通過外部類訪問到對象的內部元素
範例
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create() // 訪問到對象的內部元素
也可以這樣
class MyClass {
companion object {
}
}
val x = MyClass.Companion
注意
- 伴生對象並不是靜態成員, 是 實例成員
- 一個class裏面只能聲明一個內部關聯對象
- 即關鍵字 companion 只能使用一次
對象表達式和對象聲明之間的語義差異
- 對象表達式是在使用他們的地方
是立即執行的 - 對象聲明是在第一次被訪問到時
是延遲初始化的 - 伴生對象的初始化
是在相應的類被加載(解析)時,與 Java 靜態初始化器的語義相匹配
小結
總體來說,在Kotlin中,通過object實現了單例,並簡化了單例模式下實例的調用方式;
通過伴生對象,解決了部分的 初始化需求,但是,又在一些情況下,弱化伴生對象的存在(companion object修飾的類名可以不寫)。
將減少代碼量,作爲最高意志。