本文鏈接
本文結(jié)合自己的感受钥组,做一下簡單的翻譯输硝。原文作者也是《Kotlin for Android developer》的作者。此譯文供大家學(xué)習(xí)參考之用程梦。
Kotlin中的對象点把,創(chuàng)建安全的單例就一行代碼
先說明一個(gè)概念:
Kotlin中的object關(guān)鍵字和Java中的Object類橘荠, 不是一個(gè)東西。所以本文中的對象(object)指的是kotlin中的object關(guān)鍵字郎逃。
Kotlin對象(object)作為語言的另外一種關(guān)鍵字(要素)哥童,我們Android開發(fā)者不熟悉,因?yàn)椴幌馢ava褒翰。實(shí)際上贮懈,一個(gè)對象(object)只是單例實(shí)現(xiàn)的類型。因此我們要找和Java相似處优训,那就是單例模式朵你。我們會(huì)在下面對比一下。
單例 VS 對象
聽起來Java中的單例不是那么容易實(shí)現(xiàn)型宙。
public class Singleton {
private Singleton() {
}
private static Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
但是這個(gè)代碼是危險(xiǎn)的撬呢,特別是如果他們在不同的線程執(zhí)行的時(shí)候。如果2個(gè)線程在同一時(shí)刻訪問這個(gè)單例的話妆兑,這個(gè)對象會(huì)生成2個(gè)實(shí)例魂拦。更安全的代碼是如下:
public class Singleton {
private static Singleton instance = null;
private Singleton(){
}
private synchronized static void createInstance() {
if (instance == null) {
instance = new Singleton();
}
}
public static Singleton getInstance() {
if (instance == null) createInstance();
return instance;
}
}
如你所見,你需要一些代碼創(chuàng)建有效的單例搁嗓。
那在Kotlin中相等價(jià)的是如何實(shí)現(xiàn)的呢芯勘?
object Singleton
你不需要更多。在菜單『工具』的Kotlin中腺逛,你可以使用『顯示字節(jié)碼』工具荷愕,及反編譯選項(xiàng)。這樣棍矛,你能看到Kotlin團(tuán)隊(duì)是用什么來實(shí)現(xiàn)單例模式的(使用靜態(tài)塊來初始化單例)安疗。當(dāng)你不能肯定在這里發(fā)生了什么,我相信你記得使用工具來驗(yàn)證够委。
對象(object)定義
定義一個(gè)對象(Object)和定義一個(gè)類一樣簡單荐类。讓我們定義一個(gè)實(shí)現(xiàn)數(shù)據(jù)庫工具來作為例子:
object MySQLOpenHandler : SQLiteOpenHelper(App.instance, "MyDB", null, 1) {
override fun onCreate(db: SQLiteDatabase?) {
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
}
}
如你所見,你只需要使用關(guān)鍵詞『Object』來替代『Class』茁帽,其余一樣的玉罐。只是對象不能有構(gòu)造方法,我們通過訪問他們來調(diào)用相應(yīng)構(gòu)造方法潘拨。對象的實(shí)例會(huì)在我們第一次使用的時(shí)候創(chuàng)建吊输。因此這是惰性實(shí)現(xiàn)的:如果一個(gè)對象從來沒有被使用,那他的實(shí)例也從不會(huì)被創(chuàng)建。
Companion 伴生對象(object)
每個(gè)類都能實(shí)現(xiàn)一個(gè)伴生對象(object),是這個(gè)類所有實(shí)例共有的一個(gè)對象昙楚。這個(gè)有點(diǎn)類似Java中的靜態(tài)屬性招盲。一個(gè)實(shí)現(xiàn)的例子:
class App : Application() {
companion object {
lateinit var instance: App
private set
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
這個(gè)例子我創(chuàng)建了一個(gè)類繼承了『Application』 并且保存在他唯一實(shí)例的『companion 』對象中扭屁⊥赶酰『lateinit』修飾表明這個(gè)屬性不會(huì)一開始就有值,但是它會(huì)在使用前被賦值(重寫會(huì)被拋異常)疯搅。這個(gè)『private set』這個(gè)屬性不會(huì)被外部類賦值。
注意:你可能覺得可以用對象(object)來替代類來實(shí)現(xiàn)App埋泵,這樣Android框架需要實(shí)例化這個(gè)類幔欧。如果你試了,當(dāng)它啟動(dòng)的時(shí)候丽声,你會(huì)看到Application拋異常處理礁蔗,你需要App作為一個(gè)類。如果你要訪問的話雁社,可以創(chuàng)建一個(gè)小點(diǎn)的單例實(shí)現(xiàn)浴井。
對象(object)匿名表達(dá)式
對象可以作為匿名類實(shí)現(xiàn)。
一個(gè)例子:
recycler.adapter = object : RecyclerView.Adapter() {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
}
override fun getItemCount(): Int {
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
}
}
每當(dāng)你要?jiǎng)?chuàng)建一個(gè)接口的內(nèi)聯(lián)實(shí)現(xiàn)霉撵,例如:繼承其他類磺浙,你會(huì)使用上面的表示方式。
但是一個(gè)對象也可以作為一個(gè)類的代理徒坡。你能創(chuàng)建想下面一樣創(chuàng)建
val newObj = object {
var x = "a"
var y = "b"
}
Log.d(tag, "x:${newObj.x}, y:${newObj.y}")
結(jié)論
對象從Java6開始撕氧,對象對我們來說是一個(gè)新的概念,但是很多概念和這個(gè)有相關(guān)性喇完,因此你們需要快速理解伦泥。