kotlinのシングルトンクラスの詳しい説明

物体

シングルトンオブジェクトの宣言:

object  Model{
    
    
    var temp = "1"
    val temp2 = "2"
    const val temp3 = "3"
}

object変更されたクラスにはどのようなタイプのシングルトン パターンが使用されているのかという疑問が生じます。

javaここで最初に6 つのシングルトン パターンを確認します。

1. お腹を空かせた中華風
public class HungryMan {
    
    

    private HungryMan(){
    
    }

    private static HungryMan hungryMan = new HungryMan();

    public static HungryMan getInstance(){
    
    
        return hungryMan;
    }
}

利点: シンプルで便利、スレッドセーフ

欠点: 使用されるかどうかに関係なく、インスタンス化され、クラスがロードされるときにインスタンス化されます。

2. レイジースタイル
public class LazyMan {
    
    

    private static LazyMan lazyMan = null;

    private LazyMan() {
    
    
    }

    public static LazyMan getInstatce() {
    
    
        if (lazyMan == null) {
    
    
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }
}

利点: オブジェクトは使用されたときにのみ生成されるため、メモリのオーバーヘッドを削減できます。

欠点: スレッドは安全ではなく、単一スレッドでのみ使用でき、複数のスレッドがアクセスすると複数のオブジェクトが生成されます。

3. 遅延同期ロック
public class LazyMan {
    
    

    private static volatile LazyMan lazyMan = null;

    private LazyMan() {
    
    
    }

    public static LazyMan getInstatce() {
    
    
        synchronized (LazyMan.class){
    
    
            if (lazyMan == null) {
    
    
                lazyMan = new LazyMan();
            }
        }
        return lazyMan;
    }
}

長所: マルチスレッドをサポート

短所: ロックとリリースの操作が毎回行われるため、非効率であり、リフレクションによってシングルトン モードが破壊される可能性があります。

4.DCL二重検知ロック
public class LazyMan {
    
    

    private static volatile LazyMan lazyMan = null;

    private LazyMan() {
    
    
    }

    public static LazyMan getInstatce() {
    
    
        if(lazyMan == null){
    
    
            synchronized (LazyMan.class){
    
    
                if (lazyMan == null) {
    
    
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }
}

DCL二重検知ロック機構についてご紹介します。

DCL二重検出ロック メカニズム:変更DCLに二重検出ロック メカニズムを使用するのはvaloatilelazyMan=new LazyMan()アトミックな操作ではないためです。実際、JVM私はおそらく 3 つのことをしました。

1.lazyManメモリを割り当てるには、

2. コンストラクターを呼び出してメンバー変数を初期化します。

3.lazyManオブジェクトが割り当てられたメモリ空間を指すようにします。ただしJVM、リアルタイム コンパイラでは命令の並べ替えの最適化が行われています。つまり、上記の 2 番目と 3 番目のステップの順序が不確かです。2、3 になると、順序がめちゃくちゃになります。これは、スレッドが呼び出しを行うためです。 null ではありませんが、初期化されていないため、エラーが直接報告されます。

利点: 高効率、スレッドの安全性

欠点: コードが複雑で、シングルトンがリフレクションによって破壊される可能性がある

5. 静的内部クラス
public class Singleton {
    
    
 
    private Singleton() {
    
    }
 
    private static class SingletonInstance {
    
    //私有静态内部类
        private static final Singleton INSTANCE = new Singleton();
    }
 
    public static Singleton getInstance() {
    
    
        return SingletonInstance.INSTANCE;
    }
}

利点: クラスの静的プロパティは、クラスが初めてロードされるときにのみ初期化されるため、スレッド セーフになります。

デメリット:コードが複雑になり、apkファイルサイズが大きくなる

6. シングルトンを列挙する
public enum SingleTon {
    
    

    SINGLE_TON;

    private String field;

    public String getField() {
    
    
        return field;
    }

    public void setField(String field) {
    
    
        this.field = field;
    }
}

利点: スレッドセーフ、シングルトンモードを壊すリフレクションを心配する必要がない

欠点: 列挙型クラスは多くのメモリを消費します

分析: オブジェクト シングルトン クラスはどのタイプのシングルトンであるか

kotlinここでは、表示するためにコードを Java コードに直接変換します。

kotlinコードは以下のように表示されます

回ったJava

クラスがコードに変換された後は、空腹のシングルトンであることModelわかります。Javaしたがって、object使用されるクラスは空腹の中国のシングルトンです。

companion objectコンパニオン オブジェクトに表示されるシングルトンはどのタイプのシングルトンですか

kotlinコードは以下のように表示されます

class  Model{
    
    
    companion object{
    
    
        val text = ApiWrapper("11")
    }
}

class ApiWrapper (val api : String){
    
    
     fun s() {
    
    
      
    }
}

javaコードは以下のように表示されます

public final class Model {
    
    
   @NotNull
   private static final ApiWrapper text = new ApiWrapper("11");
   @NotNull
   public static final Model.Companion Companion = new Model.Companion((DefaultConstructorMarker)null);

   public static final class Companion {
    
    
      @NotNull
      public final ApiWrapper getText() {
    
    
         return Model.text;
      }

      private Companion() {
    
    
      }
      public Companion(DefaultConstructorMarker $constructor_marker) {
    
    
         this();
      }
   }
}

text値を直接代入すると、空腹の中華風のローディングと同等であることがわかります。

textしかし、遅延割り当てを行うby lazyどうなるでしょうか

public final class Model {
    
    
   @NotNull
   private static final Lazy text$delegate;
   @NotNull
   public static final Model.Companion Companion = new Model.Companion((DefaultConstructorMarker)null);

   static {
    
    
      text$delegate = LazyKt.lazy((Function0)null.INSTANCE);
   }

   public static final class Companion {
    
    
      @NotNull
      public final ApiWrapper getText() {
    
    
         Lazy var1 = Model.text$delegate;
         Model.Companion var2 = Model.Companion;
         Object var3 = null;
         return (ApiWrapper)var1.getValue();
      }

      private Companion() {
    
    
      }

      public Companion(DefaultConstructorMarker $constructor_marker) {
    
    
         this();
      }
   }
}

今回は となることがわかります懒汉式同步单例

なぜ同期シングルトンなのかについては、ここでLazyKt.lazy()メソッドを確認する必要があります。

おすすめ

転載: blog.csdn.net/weixin_44710164/article/details/127889022