物体
シングルトンオブジェクトの宣言:
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
に二重検出ロック メカニズムを使用するのはvaloatile
、lazyMan=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()
メソッドを確認する必要があります。