Kotlin對象:僅一行代碼就可創建安全的單例


作者:Antonio Leiva

時間:Jun 20, 2017

原文鏈接:https://antonioleiva.com/objects-kotlin/

 

 

 

Kotlin對象是Android開發人員不熟悉的另一個語言元素,因為在Java中沒有這樣的東西。

 

事實上,對象就是具有單一實現的數據類型。所以如果我們想在Java中找到類似的東西,那將是單例模式。在接下的內容中,我們將比較它們。

 

 

單例對象

 

 

 

Java中,單例不像聽起來那么容易實現。通常可能會認為是這樣:

 1 public class Singleton {
 2  
 3     private Singleton() {
 4     }
 5  
 6     private static Singleton instance;
 7  
 8     public static Singleton getInstance() {
 9         if (instance == null) {
10             instance = new Singleton();
11         }
12  
13         return instance;
14     }
15 }

 

但是,這段代碼是危險的,特別是它被用於不同的線程中。如果有兩個線程同時訪問這個單例,就有可能產生這個對象的兩個實例。安全的代碼應該是:

 

 1 public class Singleton {
 2  
 3     private static Singleton instance = null;
 4  
 5     private Singleton(){
 6     }
 7  
 8     private synchronized static void createInstance() {
 9         if (instance == null) {
10             instance = new Singleton();
11         }
12     }
13  
14     public static Singleton getInstance() {
15         if (instance == null) createInstance();
16         return instance;
17     }
18 }

 

 

如你所見,創建一個有效的單例,你需要好幾行代碼。

 

 

那么在Kotlin中是怎樣的?

1 object Singleton

 

你不需要更多的代碼。你可以用在 Tools --> Kotlin 中的 bytecode 工具展示其,然后用Decomplie 選項。也就是,你可以看到Kotlin團隊決定怎樣實現單例的。

 

 

當不確定其背后究竟發生了什么時,我建議您使用這個工具。

 

 

對象聲明

 

 

 

聲明對象就如同聲明一個類。

 

 

作為例子,讓我們來聲明一個實現數據庫幫助的對象:

 

1 object MySQLOpenHandler : SQLiteOpenHelper(App.instance, "MyDB", null, 1) {
2     
3     override fun onCreate(db: SQLiteDatabase?) {
4     }
5  
6     override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
7     }
8  
9 }

 

 

這段代碼,你只需要用保留字object替代class,其他都相同。只需要考慮到對象不能有構造函數,因為我們不調用任何構造函數來訪問它們。

 

 

對象的實例在我們第一次使用時,被創建。所以這里有一個懶惰實例化:如果一個對象永遠不會被使用,這個實例永遠不會被創建。

 

 

伴生對象(Companion Object

 

 

 

每個類都可以實現一個伴生對象,它是該類的所有實例共有的對象。它將類似於Java中的靜態字段。

 

實現的例子:

 

 1 class App : Application() {
 2     companion object {
 3         lateinit var instance: App
 4             private set
 5     }
 6  
 7     override fun onCreate() {
 8         super.onCreate()
 9         instance = this
10     }
11  
12 }

 

 

在這例子中,我創建一個由Application擴展的(派送)的類,並且在companion object中存儲它的唯一實例。

 

 

lateinit表示這個屬性開始是沒有值得,但是,在使用前將被賦值(否則,就會拋出異常)。

 

 

private set用於說明外部類不能對其進行賦值。

 

 

注意:

 

你可能會認為,若App是一個對象,而非一個類會很有意義的。如果這樣,由於Android框架實例化類的方式,在你嘗試時,你會發現應用程序啟動時就拋出異常。你需要App成為一個類,如果你想要訪問它,你可以創建一個這個小的單例。

 

對象表達式

 

對象也能用於創建匿名類實現。

 

 

例如:

 

 1 recycler.adapter = object : RecyclerView.Adapter() {
 2     override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
 3     }
 4  
 5     override fun getItemCount(): Int {
 6     }
 7  
 8     override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
 9     }
10  
11 }

 

 

例如,每次想要創建一個接口的內聯實現,或者擴展另一個類時,你將使用上面的符號。

 

但是一個對象也可以表示一個不存在的類。你可以在運行中創建它:

 

val newObj = object {
    var x = "a"
    var y = "b"
}
 
Log.d(tag, "x:${newObj.x}, y:${newObj.y}")

 

 

結論

 

對象對於Java 6開發人員來說是一個新概念,但有許多概念可以與現有的相關聯,所以你可以快速地學習使用它們。

 

如果你喜歡你讀的內容,我建議您查看以前的文章,可以學習到更多的Kotlin知識,或者在本書中,學習如何從頭開始創建完整的應用程序。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM