第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁(yè) 慕課教程 Kotlin 教程 Kotlin 教程 Kotlin 如何實(shí)現(xiàn)常用的單例模式

Kotlin 如何實(shí)現(xiàn)常用單例模式

從這篇文章開(kāi)始,我將帶領(lǐng)大家一起來(lái)進(jìn)入 Kotlin 實(shí)戰(zhàn)篇,俗話說(shuō)光說(shuō)不練假把式,下面該系列就是闡述 Kotlin 是如何用于平時(shí)的開(kāi)發(fā),這篇文章將帶領(lǐng)大家如何使用 Kotlin 實(shí)現(xiàn)常見(jiàn)的設(shè)計(jì)模式,相比 Java 實(shí)現(xiàn)設(shè)計(jì)模式,Kotlin 就會(huì)顯得簡(jiǎn)潔和高效沒(méi)有冗余的模板代碼。這篇文章介紹的是最為簡(jiǎn)單和常用的單利模式。

1. 單例模式的介紹

單例模式是開(kāi)發(fā)者最為常見(jiàn)的一種設(shè)計(jì)模式,也是 23 種設(shè)計(jì)模式中最為簡(jiǎn)單一種設(shè)計(jì)模式。大部分的開(kāi)發(fā)者都知道它的使用和原理。單例模式顧名思義就是在應(yīng)用這個(gè)模式時(shí),單例對(duì)象的類必須是只有一個(gè)對(duì)象實(shí)例存在。在一些應(yīng)用場(chǎng)景中我們只需要一個(gè)全局唯一的對(duì)象實(shí)例去調(diào)度整體行為。還有一些情況為了系統(tǒng)資源開(kāi)銷考慮,避免重復(fù)創(chuàng)建多個(gè)實(shí)例,往往采用單例模式來(lái)保證全局只有一個(gè)實(shí)例對(duì)象。

2. 單例模式的定義

保證某個(gè)類只有一個(gè)實(shí)例對(duì)象,該實(shí)例對(duì)象在內(nèi)部進(jìn)行實(shí)例化,并且提供了一個(gè)獲取該實(shí)例對(duì)象的全局訪問(wèn)點(diǎn)。

3. 單例模式的基本要求

  • 1、構(gòu)造器私有化,private 修飾,主要為了防止外部私自創(chuàng)建該單例類的對(duì)象實(shí)例
  • 2、提供一個(gè)該實(shí)例對(duì)象全局訪問(wèn)點(diǎn),在 Java 中一般是以公有的靜態(tài)方法或者枚舉返回單例類對(duì)象
  • 3、在多線程環(huán)境下保證單例類有且只有一個(gè)對(duì)象實(shí)例,以及在多線程環(huán)境下獲取單例類對(duì)象實(shí)例需要保證線程安全。
  • 4、在反序列化時(shí)保證單例類有且只有一個(gè)對(duì)象實(shí)例。

4. 單例模式的使用場(chǎng)景

一般用于確定某個(gè)類只需要一個(gè)實(shí)例對(duì)象,從而避免中了頻繁創(chuàng)建多個(gè)對(duì)象實(shí)例所帶來(lái)資源和性能開(kāi)銷。例如常見(jiàn)的數(shù)據(jù)庫(kù)連接或 IO 操作等。

5. 單例模式的 UML 類圖

圖片描述

6. 餓漢式單例

餓漢式單例模式是實(shí)現(xiàn)單例模式比較簡(jiǎn)單的一種方式,它有個(gè)特點(diǎn)就是不管需不需要該單例實(shí)例,該實(shí)例對(duì)象都會(huì)被實(shí)例化。

6.1 Kotlin 實(shí)現(xiàn)餓漢式單例

在 Kotlin 中實(shí)現(xiàn)一個(gè)餓漢式單例模式可以說(shuō)是非常非常簡(jiǎn)單,只需要定義一個(gè) object 對(duì)象表達(dá)式即可,無(wú)需手動(dòng)去設(shè)置構(gòu)造器私有化和提供全局訪問(wèn)點(diǎn),這一點(diǎn) Kotlin 編譯器全給你做好了。

object KSingleton : Serializable {//實(shí)現(xiàn)Serializable序列化接口,通過(guò)私有、被實(shí)例化的readResolve方法控制反序列化
    fun doSomething() {
        println("do some thing")
    }

    private fun readResolve(): Any {//防止單例對(duì)象在反序列化時(shí)重新生成對(duì)象
        return KSingleton//由于反序列化時(shí)會(huì)調(diào)用readResolve這個(gè)鉤子方法,只需要把當(dāng)前的KSingleton對(duì)象返回而不是去創(chuàng)建一個(gè)新的對(duì)象
    }
}

//在Kotlin中使用KSingleton
fun main(args: Array<String>) {
    KSingleton.doSomething()//像調(diào)用靜態(tài)方法一樣,調(diào)用單例類中的方法
}
//在Java中使用KSingleton
public class TestMain {
    public static void main(String[] args) {
        KSingleton.INSTANCE.doSomething();//通過(guò)拿到KSingleton的公有單例類靜態(tài)實(shí)例INSTANCE, 再通過(guò)INSTANCE調(diào)用單例類中的方法
    }
}

KSingleton 反編譯成 Java 代碼

public final class KSingleton implements Serializable {
   public static final KSingleton INSTANCE;

   public final void doSomething() {
      String var1 = "do some thing";
      System.out.println(var1);
   }

   private final Object readResolve() {
      return INSTANCE;//可以看到readResolve方法直接返回了INSTANCE而不是創(chuàng)建新的實(shí)例
   }

   static {//靜態(tài)代碼塊初始化KSingleton實(shí)例,不管有沒(méi)有使用,只要KSingleton被加載了,
   //靜態(tài)代碼塊就會(huì)被調(diào)用,KSingleton實(shí)例就會(huì)被創(chuàng)建,并賦值給INSTANCE
      KSingleton var0 = new KSingleton();
      INSTANCE = var0;
   }
}

可能會(huì)有人疑問(wèn):沒(méi)有看到構(gòu)造器私有化,實(shí)際上這一點(diǎn)已經(jīng)在編譯器層面做了限制,不管你是在 Java 還是 Kotlin 中都無(wú)法私自去創(chuàng)建新的單例對(duì)象。

6.2 Java 實(shí)現(xiàn)餓漢式單例

public class Singleton implements Serializable {
    private Singleton() {//構(gòu)造器私有化
    }

    private static final Singleton mInstance = new Singleton();

    public static Singleton getInstance() {//提供公有獲取單例對(duì)象的函數(shù)
        return mInstance;
    }

    //防止單例對(duì)象在反序列化時(shí)重新生成對(duì)象
    private Object readResolve() throws ObjectStreamException {
        return mInstance;
    }
}

對(duì)比一下 Kotlin 和 Java 的餓漢式的單例實(shí)現(xiàn)發(fā)現(xiàn),是不是覺(jué)得 Kotlin 會(huì)比 Java 簡(jiǎn)單得多得多。

7. 線程安全的懶漢式單例

可是有時(shí)候我們并不想當(dāng)類加載的時(shí)候就去創(chuàng)建這個(gè)單例實(shí)例,而是想當(dāng)我們使用這個(gè)實(shí)例的時(shí)候才去初始化它。于是乎就有了懶漢式的單例模式

7.1 Kotlin 實(shí)現(xiàn)線程安全的懶漢式單例

class KLazilySingleton private constructor() : Serializable {
    fun doSomething() {
        println("do some thing")
    }
    companion object {
        private var mInstance: KLazilySingleton? = null
            get() {
                return field ?: KLazilySingleton()
            }

        @JvmStatic
        @Synchronized//添加synchronized同步鎖
        fun getInstance(): KLazilySingleton {
            return requireNotNull(mInstance)
        }
    }
    //防止單例對(duì)象在反序列化時(shí)重新生成對(duì)象
    private fun readResolve(): Any {
        return KLazilySingleton.getInstance()
    }
}
//在Kotlin中調(diào)用
fun main(args: Array<String>) {
    KLazilySingleton.getInstance().doSomething()
}
//在Java中調(diào)用
 KLazilySingleton.getInstance().doSomething();

7.2 Java 實(shí)現(xiàn)線程安全的懶漢式單例

class LazilySingleton implements Serializable {
    private static LazilySingleton mInstance;

    private LazilySingleton() {}//構(gòu)造器私有化

    public static synchronized LazilySingleton getInstance() {//synchronized同步鎖保證多線程調(diào)用getInstance方法線程安全
        if (mInstance == null){
            mInstance = new LazilySingleton();
        }
        return mInstance;
    }
    
    private Object readResolve() throws ObjectStreamException {//防止反序列化
        return mInstance;
    }
}

8. DCL (double check lock) 改造懶漢式單例

我們知道線程安全的單例模式直接是使用 synchronized 同步鎖,鎖住 getInstance 方法,每一次調(diào)用該方法的時(shí)候都得獲取鎖,但是如果這個(gè)單例已經(jīng)被初始化了,其實(shí)按道理就不需要申請(qǐng)同步鎖了,直接返回這個(gè)單例類實(shí)例即可。于是就有了 DCL 實(shí)現(xiàn)單例方式。

8.1 Java 中 DCL 實(shí)現(xiàn)

//DCL實(shí)現(xiàn)單例模式
public class LazySingleTon implements Serializable {
    //靜態(tài)成員私有化,注意使用volatile關(guān)鍵字,因?yàn)闀?huì)存在DCL失效的問(wèn)題
    private volatile static LazySingleTon mInstance = null; 

    private LazySingleTon() { //構(gòu)造器私有化
    }

    //公有獲取單例對(duì)象的函數(shù)
    //DCL(Double Check Lock) 既能在需要的時(shí)候初始化單例,又能保證線程安全,且單例對(duì)象初始化完后,調(diào)用getInstance不需要進(jìn)行同步鎖
    public static LazySingleTon getInstance() {
        if (mInstance == null) {//為了防止單例對(duì)象初始化完后,調(diào)用getInstance再次重復(fù)進(jìn)行同步鎖
            synchronized (LazySingleTon.class) {
                if (mInstance == null) {
                    mInstance = new LazySingleTon();
                }
            }
        }

        return mInstance;
    }

    private Object readResolve() throws ObjectStreamException {
        return mInstance;
    }
}

8.2 Kotlin 中 DCL 實(shí)現(xiàn)

在 Kotlin 中有個(gè)天然特性可以支持線程安全 DCL 的單例,可以說(shuō)也是非常非常簡(jiǎn)單,就僅僅 3 行代碼左右,那就是 Companion Object + lazy 屬性代理,一起來(lái)看下吧。

class KLazilyDCLSingleton private constructor() : Serializable {//private constructor()構(gòu)造器私有化

    fun doSomething() {
        println("do some thing")
    }

    private fun readResolve(): Any {//防止單例對(duì)象在反序列化時(shí)重新生成對(duì)象
        return instance
    }
    
    companion object {
        //通過(guò)@JvmStatic注解,使得在Java中調(diào)用instance直接是像調(diào)用靜態(tài)函數(shù)一樣,
        //類似KLazilyDCLSingleton.getInstance(),如果不加注解,在Java中必須這樣調(diào)用: KLazilyDCLSingleton.Companion.getInstance().
        @JvmStatic
        //使用lazy屬性代理,并指定LazyThreadSafetyMode為SYNCHRONIZED模式保證線程安全
        val instance: KLazilyDCLSingleton by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { KLazilyDCLSingleton() }
    }
}

//在Kotlin中調(diào)用,直接通過(guò)KLazilyDCLSingleton類名調(diào)用instance
fun main(args: Array<String>) {
    KLazilyDCLSingleton.instance.doSomething()
}
//在Java中調(diào)用
public class TestMain {
    public static void main(String[] args) {
    //加了@JvmStatic注解后,可以直接KLazilyDCLSingleton.getInstance(),不會(huì)打破Java中調(diào)用習(xí)慣,和Java調(diào)用方式一樣。
       KLazilyDCLSingleton.getInstance().doSomething();
       //沒(méi)有加@JvmStatic注解,只能這樣通過(guò)Companion調(diào)用
       KLazilyDCLSingleton.Companion.getInstance().doSomething();
    }
}

注意:建議上面例子中添加 @JvmStatic 注解,Kotlin 這門(mén)語(yǔ)言可謂是操碎了心,做的很小心翼翼,為了不讓 Java 開(kāi)發(fā)者打破他們的調(diào)用習(xí)慣,讓調(diào)用根本無(wú)法感知到是 Kotlin 編寫(xiě),因?yàn)橥獠空{(diào)用方式和 Java 方式一樣。如果硬生生把 Companion 對(duì)象暴露給 Java 開(kāi)發(fā)者他們可能會(huì)感到一臉懵逼。

可能大家對(duì) lazy 和 Companion Object 功能強(qiáng)大感到一臉懵,讓我們一起瞅瞅反編譯后的 Java 代碼你就會(huì)恍然大悟了:

public final class KLazilyDCLSingleton implements Serializable {
   @NotNull
   private static final Lazy instance$delegate;
   //Companion提供公有全局訪問(wèn)點(diǎn),KLazilyDCLSingleton.Companion實(shí)際上一個(gè)餓漢式的單例模式
   public static final KLazilyDCLSingleton.Companion Companion = new KLazilyDCLSingleton.Companion((DefaultConstructorMarker)null);
   public final void doSomething() {
      String var1 = "do some thing";
      System.out.println(var1);
   }

   private final Object readResolve() {
      return Companion.getInstance();
   }

   private KLazilyDCLSingleton() {
   }

   static {//注意: 可以看到靜態(tài)代碼塊中并不是初始化KLazilyDCLSingleton的instance而是初始化它的Lazy代理對(duì)象,說(shuō)明KLazilyDCLSingleton類被加載了,
   //但是KLazilyDCLSingleton的instance并沒(méi)有被初始化,符合懶加載規(guī)則,那么什么時(shí)候初始化instance這就涉及到了屬性代理知識(shí)了,下面會(huì)做詳細(xì)分析
      instance$delegate = LazyKt.lazy(LazyThreadSafetyMode.SYNCHRONIZED, (Function0)null.INSTANCE);
   }

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

   @NotNull
   public static final KLazilyDCLSingleton getInstance() {
      return Companion.getInstance();//這里可以看到加了@JvmStatic注解后,getInstance內(nèi)部把我們省略Companion.getInstance()這一步,這樣一來(lái)Java調(diào)用者就直接KLazilyDCLSingleton.getInstance()獲取單例實(shí)例
   }

   //Companion靜態(tài)內(nèi)部類實(shí)際上也是一個(gè)單例模式
   public static final class Companion {
      // $FF: synthetic field
      static final KProperty[] ?delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(KLazilyDCLSingleton.Companion.class), "instance", "getInstance()Lcom/mikyou/design_pattern/singleton/kts/KLazilyDCLSingleton;"))};

      /** @deprecated */
      // $FF: synthetic method
      @JvmStatic
      public static void instance$annotations() {
      }

      @NotNull
      //這個(gè)方法需要注意,最終instance初始化和獲取將在這里進(jìn)行
      public final KLazilyDCLSingleton getInstance() {
         //拿到代理對(duì)象
         Lazy var1 = KLazilyDCLSingleton.instance$delegate;
         KProperty var3 = ?delegatedProperties[0];
         //代理對(duì)象的getValue方法就是初始化instance和獲取instance的入口。內(nèi)部會(huì)判斷instance是否被初始化過(guò)沒(méi)有就會(huì)返回新創(chuàng)建的對(duì)象,
         //初始化過(guò)直接返回上一次初始化的對(duì)象。所以只有真正調(diào)用getInstance方法需要這個(gè)實(shí)例的時(shí)候instance才會(huì)被初始化。
         return (KLazilyDCLSingleton)var1.getValue();
      }

      private Companion() {//Companion構(gòu)造器私有化
      }

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

8.3 Kotlin 的 lazy 屬性代理內(nèi)部實(shí)現(xiàn)源碼分析

//expect關(guān)鍵字標(biāo)記這個(gè)函數(shù)是平臺(tái)相關(guān),我們需要找到對(duì)應(yīng)的actual關(guān)鍵字實(shí)現(xiàn)表示平臺(tái)中一個(gè)相關(guān)實(shí)現(xiàn) 
public expect fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T>

//對(duì)應(yīng)多平臺(tái)中一個(gè)平臺(tái)相關(guān)實(shí)現(xiàn)lazy函數(shù)
public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
    when (mode) {//根據(jù)不同mode,返回不同的Lazy的實(shí)現(xiàn),我們重點(diǎn)看下SynchronizedLazyImpl
        LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
        LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
        LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
    }

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//為了解決DCL帶來(lái)指令重排序?qū)е轮鞔婧凸ぷ鲀?nèi)存數(shù)據(jù)不一致的問(wèn)題,這里使用Volatile原語(yǔ)注解。具體Volatile為什么能解決這樣的問(wèn)題請(qǐng)接著看后面的分析
    private val lock = lock ?: this

    override val value: T
        get() {//當(dāng)外部調(diào)用value值,get訪問(wèn)器會(huì)被調(diào)用
            val _v1 = _value
            if (_v1 !== UNINITIALIZED_VALUE) {//進(jìn)行第一層的Check, 如果這個(gè)值已經(jīng)初始化過(guò)了,直接返回_v1,避免走下面synchronized獲取同步鎖帶來(lái)不必要資源開(kāi)銷。
                @Suppress("UNCHECKED_CAST")
                return _v1 as T
            }

            return synchronized(lock) {
                val _v2 = _value
                if (_v2 !== UNINITIALIZED_VALUE) {//進(jìn)行第二層的Check,主要是為了_v2被初始化直接返回
                    @Suppress("UNCHECKED_CAST") (_v2 as T)
                } else {
                //如果沒(méi)有初始化執(zhí)行initializer!!() lambda, 
                //實(shí)際上相當(dāng)于執(zhí)行外部調(diào)用傳入的 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { KLazilyDCLSingleton() } 中的KLazilyDCLSingleton()也即是返回KLazilyDCLSingleton實(shí)例對(duì)象
                    val typedValue  initializer!!()
                    _value = typedValue//并把這個(gè)實(shí)例對(duì)象保存在_value中
                    initializer = null
                    typedValue
                }
            }
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE

    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."

    private fun writeReplace(): Any = InitializedLazyImpl(value)
}

8.4 DCL 存在多線程安全問(wèn)題分析及解決

DCL 存在多線程安全問(wèn)題,我們都知道線程安全主要來(lái)自主存和工作內(nèi)存數(shù)據(jù)不一致以及重排序 (指令重排序或編譯器重排序造成的)。那么 DCL 存在什么問(wèn)題呢?
首先,mInstance = new LazySingleton() 不是一個(gè)原子操作而是分為三步進(jìn)行:

  • 1、給 LazySingleton 實(shí)例分配內(nèi)存;
  • 2、調(diào)用 LazySingleton 的構(gòu)造函數(shù),初始化成員字段;
  • 3、將 mInstance 對(duì)象引用指向分配的內(nèi)存空間 (此時(shí) mInstance 不為 null)。

在 JDK1.5 之前版本的 Java 內(nèi)存模型中,Cache, 寄存器到主存回寫(xiě)順序規(guī)則,無(wú)法保證第 2 和第 3 執(zhí)行的順序,可能是 1-2-3,也有可能是 1-3-2。

若 A 線程先執(zhí)行了第 1 步,第 3 步,此時(shí)切換到 B 線程,由于 A 線程中已經(jīng)執(zhí)行了第 3 步所以 mInstance 不為 null,那么 B 線程中直接把 mInstance 取走,由于并沒(méi)有執(zhí)行第 2 步使用的時(shí)候就會(huì)報(bào)錯(cuò)。

為了解決該問(wèn)題,JDK1.5 之后,具體化了 volatile 關(guān)鍵字,能夠確保每次都是從主存獲取最新有效值。所以需要 private volatile static LazySingleTon mInstance = null;

9. 靜態(tài)內(nèi)部類單例

DCL 雖然在一定程度上能解決資源消耗、多余 synchronized 同步、線程安全等問(wèn)題,但是某些情況下還會(huì)存在 DCL 失效問(wèn)題,盡管在 JDK1.5 之后通過(guò)具體化 volatile 原語(yǔ)來(lái)解決 DCL 失效問(wèn)題,但是它始終并不是優(yōu)雅一種解決方式,在多線程環(huán)境下一般不推薦 DCL 的單例模式。所以引出靜態(tài)內(nèi)部類單例實(shí)現(xiàn)

9.1 Kotlin 實(shí)現(xiàn)靜態(tài)內(nèi)部類單例

class KOptimizeSingleton private constructor(): Serializable {//private constructor()構(gòu)造器私有化
    companion object {
        @JvmStatic
        fun getInstance(): KOptimizeSingleton {//全局訪問(wèn)點(diǎn)
            return SingletonHolder.mInstance
        }
    }

    fun doSomething() {
        println("do some thing")
    }
    
    private object SingletonHolder {//靜態(tài)內(nèi)部類
        val mInstance: KOptimizeSingleton = KOptimizeSingleton()
    }
    
    private fun readResolve(): Any {//防止單例對(duì)象在反序列化時(shí)重新生成對(duì)象
        return SingletonHolder.mInstance
    }
}

9.2 Java 實(shí)現(xiàn)靜態(tài)內(nèi)部類單例

//使用靜態(tài)內(nèi)部單例模式
public class OptimizeSingleton implements Serializable {
    //構(gòu)造器私有化
    private OptimizeSingleton() {
    }

    //靜態(tài)私有內(nèi)部類
    private static class SingletonHolder {
        private static final OptimizeSingleton sInstance = new OptimizeSingleton();
    }

    //公有獲取單例對(duì)象的函數(shù)
    public static OptimizeSingleton getInstance() {
        return SingletonHolder.sInstance;
    }
    
    public void doSomeThings() {
        System.out.println("do some things");
    }
    
    //防止反序列化重新創(chuàng)建對(duì)象
    private Object readResolve() {
        return SingletonHolder.sInstance;
    }
}

10. 枚舉單例

其實(shí)細(xì)心的小伙伴就會(huì)觀察到上面例子中我都會(huì)去實(shí)現(xiàn) Serializable 接口,并且會(huì)去實(shí)現(xiàn) readResolve 方法。這是為了反序列化會(huì)重新創(chuàng)建對(duì)象而使得原來(lái)的單例對(duì)象不再唯一。

通過(guò)序列化一個(gè)單例對(duì)象將它寫(xiě)入到磁盤(pán)中,然后再?gòu)拇疟P(pán)中讀取出來(lái),從而可以獲得一個(gè)新的實(shí)例對(duì)象,即使構(gòu)造器是私有的,反序列化會(huì)通過(guò)其他特殊途徑創(chuàng)建單例類的新實(shí)例。然而為了讓開(kāi)發(fā)者能夠控制反序列化,提供一個(gè)特殊的鉤子方法那就是 readResolve 方法,這樣一來(lái)我們只需要在 readResolve 直接返回原來(lái)的實(shí)例即可,就不會(huì)創(chuàng)建新的對(duì)象。

枚舉單例實(shí)現(xiàn),就是為了防止反序列化,因?yàn)槲覀兌贾烂杜e類反序列化是不會(huì)創(chuàng)建新的對(duì)象實(shí)例的。 Java 的序列化機(jī)制對(duì)枚舉類型做了特殊處理,一般來(lái)說(shuō)在序列枚舉類型時(shí),只會(huì)存儲(chǔ)枚舉類的引用和枚舉常量名稱,反序列化的過(guò)程中,這些信息被用來(lái)在運(yùn)行時(shí)環(huán)境中查找存在的枚舉類型對(duì)象,枚舉類型的序列化機(jī)制保證只會(huì)查找已經(jīng)存在的枚舉類型實(shí)例,而不是創(chuàng)建新的實(shí)例。

10.1 Kotlin 實(shí)現(xiàn)枚舉單例

enum class KEnumSingleton {
    INSTANCE;

    fun doSomeThing() {
        println("do some thing")
    }
}
//在Kotlin中調(diào)用
fun main(args: Array<String>) {
    KEnumSingleton.INSTANCE.doSomeThing()
}
//在Java中調(diào)用
 KEnumSingleton.INSTANCE.doSomeThing();

10.2 Java 實(shí)現(xiàn)枚舉單例

public enum EnumSingleton {
    INSTANCE;
    public void doSomeThing() {
        System.out.println("do some thing");
    }
}

//調(diào)用方式
EnumSingleton.INSTANCE.doSomeThing();

11. 總結(jié)

到這里有關(guān) Kotlin 實(shí)現(xiàn)常見(jiàn)的單例模式就闡述完畢,這篇文章通過(guò)與 Java 對(duì)比,并用幾種常見(jiàn)單例模式舉例對(duì)比 Kotlin 和 Java 實(shí)現(xiàn)。下篇文章將繼續(xù)設(shè)計(jì)模式中代理模式,看看 Kotlin 為代理模式帶來(lái)什么神奇的魔法。