這篇文章給大家介紹Kotlin中的單例模式有哪些,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
創新互聯的客戶來自各行各業,為了共同目標,我們在工作上密切配合,從創業型小企業到企事業單位,感謝他們對我們的要求,感謝他們從不同領域給我們帶來的挑戰,讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。專業領域包括網站制作、做網站、電商網站開發、微信營銷、系統平臺開發。
一、餓漢式實現
//Java實現 public class SingletonDemo { private static SingletonDemo instance=new SingletonDemo(); private SingletonDemo(){ } public static SingletonDemo getInstance(){ return instance; } } //Kotlin實現 object SingletonDemo
這里很多小伙伴,就吃了一驚。我靠一個object 關鍵字就完成相同的功能?一行代碼?
Kotlin的對象聲明
學習了Kotlin的小伙伴肯定知道,在Kotlin中類沒有靜態方法。如果你需要寫一個可以無需用一個類的實例來調用,但需要訪問類內部的函數(例如,工廠方法,單例等),你可以把該類聲明為一個對象。該對象與其他語言的靜態成員是類似的。如果你想了解Kotlin對象聲明的更多內容。請點擊- - - 傳送門
到這里,如果還是有很多小伙伴不是很相信一行代碼就能解決這個功能,我們可以通過一下方式查看Kotlin的字節碼。
查看Kotlin對應字節碼
我們進入我們的Android Studio(我的Android Studio 3.0,如果你的編譯器版本過低,請自動升級) 選擇Tools工具欄,選擇"Kotlin",選擇“Show Kotlin Bytecode"
選擇過后就會進入到下方界面:
點擊"Decompile" 根據字節碼得到以下代碼
public final class SingletonDemo { public static final SingletonDemo INSTANCE; private SingletonDemo(){} static { SingletonDemo var0 = new SingletonDemo(); INSTANCE = var0; } }
通過以上代碼,我們了解事實就是這個樣子的,使用Kotlin"object"進行對象聲明與我們的餓漢式單例的代碼是相同的。
二、懶漢式
//Java實現 public class SingletonDemo { private static SingletonDemo instance; private SingletonDemo(){} public static SingletonDemo getInstance(){ if(instance==null){ instance=new SingletonDemo(); } return instance; } } //Kotlin實現 class SingletonDemo private constructor() { companion object { private var instance: SingletonDemo? = null get() { if (field == null) { field = SingletonDemo() } return field } fun get(): SingletonDemo{ //細心的小伙伴肯定發現了,這里不用getInstance作為為方法名,是因為在伴生對象聲明時,內部已有getInstance方法,所以只能取其他名字 return instance!! } } }
上述代碼中,我們可以發現在Kotlin實現中,我們讓其主構造函數私有化并自定義了其屬性訪問器,其余內容大同小異。
如果有小伙伴不清楚Kotlin構造函數的使用方式。請點擊 - - - 構造函數
不清楚Kotlin的屬性與訪問器,請點擊 - - -屬性和字段
三、線程安全的懶漢式
//Java實現 public class SingletonDemo { private static SingletonDemo instance; private SingletonDemo(){} public static synchronized SingletonDemo getInstance(){//使用同步鎖 if(instance==null){ instance=new SingletonDemo(); } return instance; } } //Kotlin實現 class SingletonDemo private constructor() { companion object { private var instance: SingletonDemo? = null get() { if (field == null) { field = SingletonDemo() } return field } @Synchronized fun get(): SingletonDemo{ return instance!! } } }
大家都知道在使用懶漢式會出現線程安全的問題,需要使用使用同步鎖,在Kotlin中,如果你需要將方法聲明為同步,需要添加**@Synchronized**注解。
四、雙重校驗鎖式(Double Check)
//Java實現 public class SingletonDemo { private volatile static SingletonDemo instance; private SingletonDemo(){} public static SingletonDemo getInstance(){ if(instance==null){ synchronized (SingletonDemo.class){ if(instance==null){ instance=new SingletonDemo(); } } } return instance; } } //kotlin實現 class SingletonDemo private constructor() { companion object { val instance: SingletonDemo by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SingletonDemo() } } }
哇!小伙伴們驚喜不,感不感動啊。我們居然幾行代碼就實現了多行的Java代碼。其中我們運用到了Kotlin的延遲屬性 Lazy。
Lazy是接受一個 lambda 并返回一個 Lazy 實例的函數,返回的實例可以作為實現延遲屬性的委托: 第一次調用 get() 會執行已傳遞給 lazy() 的 lambda 表達式并記錄結果, 后續調用 get() 只是返回記錄的結果。
這里還有有兩個額外的知識點。
高階函數,高階函數是將函數用作參數或返回值的函數(我很糾結我到底講不講,哎)。大家還是看這個 ---高階函數
委托屬性
如果你了解以上知識點,我們直接來看Lazy的內部實現。
Lazy內部實現
public fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> = when (mode) { LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer) LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer) LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer) }
觀察上述代碼,因為我們傳入的mode = LazyThreadSafetyMode.SYNCHRONIZED,
那么會直接走 SynchronizedLazyImpl,我們繼續觀察SynchronizedLazyImpl。
Lazy接口
SynchronizedLazyImpl實現了Lazy接口,Lazy具體接口如下:
public interface Lazy<out T> { //當前實例化對象,一旦實例化后,該對象不會再改變 public val value: T //返回true表示,已經延遲實例化過了,false 表示,沒有被實例化, //一旦方法返回true,該方法會一直返回true,且不會再繼續實例化 public fun isInitialized(): Boolean }
繼續查看SynchronizedLazyImpl,具體實現如下:
SynchronizedLazyImpl內部實現
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable { private var initializer: (() -> T)? = initializer @Volatile private var _value: Any? = UNINITIALIZED_VALUE // final field is required to enable safe publication of constructed instance private val lock = lock ?: this override val value: T get() { val _v1 = _value //判斷是否已經初始化過,如果初始化過直接返回,不在調用高級函數內部邏輯 if (_v1 !== UNINITIALIZED_VALUE) { @Suppress("UNCHECKED_CAST") return _v1 as T } return synchronized(lock) { val _v2 = _value if (_v2 !== UNINITIALIZED_VALUE) { @Suppress("UNCHECKED_CAST") (_v2 as T) } else { val typedValue = initializer!!()//調用高級函數獲取其返回值 _value = typedValue //將返回值賦值給_value,用于下次判斷時,直接返回高級函數的返回值 initializer = null typedValue } } } //省略部分代碼 }
通過上述代碼,我們發現 SynchronizedLazyImpl 覆蓋了Lazy接口的value屬性,并且重新了其屬性訪問器。其具體邏輯與Java的雙重檢驗是類似的。
到里這里其實大家還是肯定有疑問,我這里只是實例化了SynchronizedLazyImpl對象,并沒有進行值的獲取,它是怎么拿到高階函數的返回值呢?。這里又涉及到了委托屬性。
委托屬性語法是: val/var <屬性名>: <類型> by <表達式>。在 by 后面的表達式是該 委托, 因為屬性對應的 get()(和 set())會被委托給它的 getValue() 和 setValue() 方法。 屬性的委托不必實現任何的接口,但是需要提供一個 getValue() 函數(和 setValue()——對于 var 屬性)。
而Lazy.kt文件中,聲明了Lazy接口的getValue擴展函數。故在最終賦值的時候會調用該方法。
@kotlin.internal.InlineOnly //返回初始化的值。 public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
五、靜態內部類式
//Java實現 public class SingletonDemo { private static class SingletonHolder{ private static SingletonDemo instance=new SingletonDemo(); } private SingletonDemo(){ System.out.println("Singleton has loaded"); } public static SingletonDemo getInstance(){ return SingletonHolder.instance; } } //kotlin實現 class SingletonDemo private constructor() { companion object { val instance = SingletonHolder.holder } private object SingletonHolder { val holder= SingletonDemo() } }
靜態內部類的實現方式,也沒有什么好說的。Kotlin與Java實現基本雷同。
關于Kotlin中的單例模式有哪些就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
當前標題:Kotlin中的單例模式有哪些
分享URL:http://m.newbst.com/article38/jpjgpp.html
成都網站建設公司_創新互聯,為您提供商城網站、企業網站制作、網站營銷、ChatGPT、軟件開發、響應式網站
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯