2017-11-10 169 views
3

我試圖將我的項目的一部分從java轉換爲kotlin。其中之一是單身經理班。 Java類看起來像這樣kotlin的lateinit,lazy和singleton模式

public class Manager { 
    private static volatile Manager Instance = null; 
    private static final Object InstanceLock = new Object(); 
    private Manager(Object1 object1, Object2 object2, Object3 object3){//...}; 
    public static boolean isInitialized(){ 
    synchronized(InstanceLock){ 
     return Instance == null; 
    } 
    } 
    public static void initialize(Object1 object1, Object2 object2, Object3 object3){ 
     if(Instance == null){ 
     synchronized(InstanceLock){ 
      if(Instance == null){Instance = new Manager(object1, object2, object3}; 
     } 
     } 
    } 
    public static getInstance(){ 
     Precondition.checkNotNull(Instance, msg...); 
     return Instance; 
    } 
} 

另外,我反編譯.kt回Java。在伴侶類中,我獲得了以下代碼。

public static final class Companion { 
    @Nullable 
    public final Manager getInstance() { 
    return Manager.instance; 
    } 

    private final void setInstance(Manager var1) { 
    Manager.instance = var1; 
    } 

    private final Object getInstanceLock() { 
    return Manager.InstanceLock; 
    } 

    public final boolean isInitialized() { 
    Object var1 = Manager.Companion.getInstanceLock(); 
    synchronized(var1){} 

    boolean var4; 
    try { 
     var4 = Manager.Companion.getInstance() == null; 
    } finally { 
     ; 
    } 

    return var4; 
    } 

    public final void initialize(@NotNull String string1, @NotNull String string2) { 
    Intrinsics.checkParameterIsNotNull(string1, "string1"); 
    Intrinsics.checkParameterIsNotNull(string2, "string2"); 
    if (((Manager.Companion)this).getInstance() == null) { 
     Object var3 = ((Manager.Companion)this).getInstanceLock(); 
     synchronized(var3){} 

     try { 
      if (Manager.Companion.getInstance() == null) { 
       Manager.Companion.setInstance(new Manager(string1, string2, (DefaultConstructorMarker)null)); 
      } 

      Unit var5 = Unit.INSTANCE; 
     } finally { 
      ; 
     } 
    } 

    } 

    private Companion() { 
    } 

    // $FF: synthetic method 
    public Companion(DefaultConstructorMarker $constructor_marker) { 
    this(); 
    } 

}

1)如何實現線程安全的,單用lateinit或懶惰的科特林同伴對象裏面?正如我所看到的,反編譯的java代碼在初始化函數中有一個同步調用,但在同步主體中沒有任何內容。

2)我認爲kotlin對象/懶惰帶有線程安全保證,我如何在雙重檢查的鎖定模式中利用它?

3)是否有比雙重檢查鎖定模式更好的模式?假設構造函數確實需要參數。

4)由於我試圖將這個管理器類轉換爲儘可能小的kotlin文件(這個管理器文件應該與其餘的java代碼一起工作)的影響,什麼是最好的方法?我發現我要補充@Jvmstatic@Jvmfield同伴對象內的一些其他變量或函數,這樣我就不必更新已調用這些靜態字段經理其他的java文件。

5)額外的問題,如果這位經理現在在純kotlin環境中工作,那麼使用多個參數實現單例類的最佳做法是什麼?

回答

0

我沒有回答所有的問題,但是有一種定義的方式可以在Kotlin中創建一個單例類。

而不是class前面的類名前面,使用object

例如,

object Manager { 
    // your implementation 
} 

這使這個類單身,你可以直接使用這個從Java就像Manager.getInstance()(我不記得確切的語法但這應該工作)。 Kotlin爲你創造它。

您可以檢查this以獲取更多參考。

希望它能幫助你一點。

1

第一個答案沒有解決同步問題,順便說一句,它仍然是一個不甚明顯的複雜性。仍然有很多人跑來跑去說簡單地做雙重鎖定。但是有一些非常有說服力的觀點表明DCL並不總是有效。

不過,有趣的是,我最近也遇到了同樣的問題,發現this article。雖然我不喜歡這樣,我第一次發現了它,我重新審視了幾次,並加熱到它,在很大程度上是因爲:

  • 筆者就從科特林STDLIB
  • 的有碼結果是一個參數化機制,而那種難看得到的重用,這是非常引人注目的

注意的重大問題都在這個治療開始討論:

  • 同步
  • 複雜的初始化
  • 參數初始化
  • (在Android中,在上下文神對象是抹不去的關鍵)編譯後的代碼

總之,我認爲這是相當多的這第一個和最後一個字主題,令人驚訝的是,在中等發現。