【Kotlin】目前最詳細的雙語言(Java與Kotlin)5種單例模式教程

一傀履、前言

單例模式,一直以來是我們在日常開發(fā)中最常用的一種設計模式莉炉,更是面試中非常重要钓账,也非常容易被問到的問題。在日常開發(fā)中絮宁,大家常用的語言還是Java梆暮,但今天我給大家?guī)淼氖窃贙otlin語言中,單例模式是怎么編寫的绍昂,并且會對比Java方式啦粹,并說明每種方式的優(yōu)缺點。

下面會列舉5種最為常見的單例模式做對比:

  • 1.餓漢式
  • 2.懶漢式
  • 3.同步鎖式
  • 4.雙重檢測式
  • 5.內部類式

二窘游、Java與Kotlin對比

1卖陵、餓漢式

餓漢式可以說是我們最先接觸單例模式的例子了,是最基本的單例寫法张峰,也是最快最懶的方式。

優(yōu)點 缺點
簡單好寫 類加載就初始化了對象棒旗,影響應用啟動速度

下面直接看代碼吧:

Java方式

public class BaseSingleton {
    //第一步:私有構造
    private BaseSingleton() {

    }

    //第二步:私有靜態(tài)對象
    private static BaseSingleton INSTANCE = new BaseSingleton();

    //第三步:提供對外獲取方法
    public static BaseSingleton getInstance() {
        return INSTANCE;
    }
}

Kotlin方式

object BaseSingleton {

}

有童鞋要說了喘批,這什么都沒寫呀撩荣。對,餓漢式在Kotlin中饶深,只需要一個object修飾符就行了餐曹,這就是Kotlin非常厲害的地方。

2.懶漢式

針對餓漢式的缺點敌厘,于是懶漢式就出現(xiàn)了台猴,因為比較簡單,下面直接分析俱两。

優(yōu)點 缺點
只有第一次使用時饱狂,才會初始化對象 線程非安全,多線程中可能會出現(xiàn)創(chuàng)建多個對象

Java方式

public class LazyLoadSingleton {
    //第一步:私有構造
    private LazyLoadSingleton() {

    }
    //第二步:創(chuàng)建私有構造對象
    private static LazyLoadSingleton INSTANCE;

    //第二步:提供對外獲取方法
    public static LazyLoadSingleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new LazyLoadSingleton();
        }
        return INSTANCE;
    }
}

其實就是增加了一個空判斷宪彩。

Kotlin方式

class LazyLoadSingleton private constructor(){

    companion object {
        //原生寫法
        //LazyThreadSafetyMode.NONE 線程不安全
        val INSTANCE_1 by lazy(LazyThreadSafetyMode.NONE) {
            LazyLoadSingleton()
        }

        //翻譯JAVA的寫法
        private var INSTANCE_2: LazyLoadSingleton? = null

        fun getInstance(): LazyLoadSingleton {
            if (INSTANCE_2 == null) {
                INSTANCE_2 = LazyLoadSingleton()
            }
            return INSTANCE_2!!
        }
    }
}

Kotlin這里有兩種寫法休讳,一種是純種,一種是變種尿孔。變種大家一看就明白俊柔,就是直接把Java的方式翻譯過來了。純種的我們使用了lazy活合,看英文就知道是懶加載的方式雏婶,傳入了一個LazyThreadSafetyMode.NONE,英文好的小伙伴一看就明白白指,這是線程不安全的意思留晚。companion object的意思相當于Java中public static。

3.同步鎖式

因為懶漢式的出現(xiàn)侵续,雖然解決了餓漢式的不足倔丈,但也出現(xiàn)了多線程的問題。于是解決懶漢式的方式就出現(xiàn)了状蜗,那就是我們熟知的加鎖Synchronized需五。

優(yōu)點 缺點
保證線程安全 每次都要加鎖,獲取的時候不經(jīng)濟

Java方式

public class LazySynchronizedSingleton {
    //第一步:私有構造
    private LazySynchronizedSingleton() {

    }

    //第二步:創(chuàng)建私有對象
    private static LazySynchronizedSingleton INSTANCE;

    //第三步:提供對外訪問方法
    public static synchronized LazySynchronizedSingleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new LazySynchronizedSingleton();
        }
        return INSTANCE;
    }
}

只是加了一個關鍵字synchronized轧坎,沒有難理解的地方宏邮。

Kotlin方式

class LazySynchronizedSingleton private constructor(){
    companion object {
        private var INSTANCE: LazySynchronizedSingleton? = null

        //在Kotlin中,我們就用的注釋方式來加鎖
        @Synchronized
        fun getInstance(): LazySynchronizedSingleton {
            if (INSTANCE == null) {
                INSTANCE = LazySynchronizedSingleton()
            }
            return INSTANCE!!
        }
    }
}

在Kotlin中缸血,我們要使用的是注解方式@Synchronized蜜氨,就能達到同步鎖的目的了。

4.雙重檢測式

第3種方式應該已經(jīng)滿足日常大部分的需求捎泻,但對我們程序員來說飒炎,不斷的優(yōu)化才是學習之道。那么針對每次獲取都會加鎖的問題笆豁,要怎么解決呢郎汪?雙重檢測式就出現(xiàn)了赤赊。

優(yōu)點 缺點
第一次獲取的時候才會加鎖 寫法有點難,考點記性

Java方式

public class DoubleCheckSingleton {
    //第一步:私有構造
    private DoubleCheckSingleton() {

    }
    //第二步:創(chuàng)建靜態(tài)對象
    private static volatile DoubleCheckSingleton INSTANCE;

    //第三步:對外公開獲取方法
    public static DoubleCheckSingleton getInstance() {
        if (INSTANCE == null) {
            synchronized (DoubleCheckSingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new DoubleCheckSingleton();
                }
            }
        }
        return INSTANCE;
    }
}

細心的童鞋發(fā)現(xiàn)煞赢,我們第二步用到了volatile抛计,關于volatile不是本文的重點,所以這里不展開說明照筑。在第三步中吹截,我們首先判斷一次空,如果是空凝危,就加鎖波俄,然后再判斷一次空,如果為空就創(chuàng)建媒抠。這樣的好處就是上面優(yōu)點說到的弟断,只會鎖一次。缺點大家也發(fā)現(xiàn)了趴生,不僅要必須寫volatile阀趴,方法中的步驟也不能錯。

Kotlin方式

class DoubleCheckSingleton private constructor() {
    companion object {
        //Kotlin原生寫法
        val INSTANCE_1 by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            DoubleCheckSingleton()
        }

        //翻譯JAVA代碼寫法
        @Volatile
        private var INSTANCE_2: DoubleCheckSingleton? = null

        fun getInstance(): DoubleCheckSingleton {
            if (INSTANCE_2 == null) {
                synchronized(DoubleCheckSingleton::class) {
                    if (INSTANCE_2 == null) {
                        INSTANCE_2 = DoubleCheckSingleton()
                    }
                }
            }
            return INSTANCE_2!!
        }
    }
}

又來兩種寫法苍匆,變種的我就不解釋了刘急。純種的,我們只改變了lazy的括號的值浸踩,mode = LazyThreadSafetyMode.SYNCHRONIZED就是鎖的意思叔汁,英文好的童鞋一眼就明白了。

5.內部類式

最后一種方式检碗,不僅滿足了懶加載据块、線程安全,代碼也非常少折剃,是非常推薦的一種方式另假。

優(yōu)點 缺點
簡單,代碼少 暫無

Java方式

public class InnerStaticSingleton {
    private InnerStaticSingleton() {

    }

    private static class Holder {
        private static InnerStaticSingleton INSTANCE = new InnerStaticSingleton();
    }

    public static InnerStaticSingleton getInstance() {
        return Holder.INSTANCE;
    }

內部類Holder怕犁,里面有外部的實例边篮。很多童鞋可能要問,這怎么就滿足懶漢式和線程安全呢奏甫?當我們應用初始化時戈轿,getInstance沒有被調用,就沒有實例對象阵子,那就滿足了懶漢式思杯。當我們調用getInstance的時候,Java虛擬機為了保證類加載的安全性挠进,所以這里就保證了線程安全智蝠。這種寫法是不是驚呆了腾么?那Kotlin又是怎么樣寫的呢?

Kotlin方式

class InnerStaticSingleton private constructor() {
    companion object {
        fun getInstance() = Holder.INSTANCE

    }

    private object Holder {
        val INSTANCE = InnerStaticSingleton()
    }
}

很簡單杈湾,內部用object創(chuàng)建一個內部Holder單例,外部一個getInstance來獲取的方法攘须。也相當于是Java翻譯過來的方式漆撞。

三、總結

為了方便大家于宙,我創(chuàng)建了一個項目浮驳,專門供大家對比學習。

這是Github項目捞魁,里面有詳細的代碼注釋至会。如果對你有幫助,歡迎大家star谱俭,謝謝奉件!

https://github.com/FynnJason/FiveSingletonDemo

如果本文對你有幫助,歡迎點贊昆著,贊賞請我喝杯Java...

如果有什么疑問县貌,下方評論留言...

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市凑懂,隨后出現(xiàn)的幾起案子煤痕,更是在濱河造成了極大的恐慌,老刑警劉巖接谨,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摆碉,死亡現(xiàn)場離奇詭異,居然都是意外死亡脓豪,警方通過查閱死者的電腦和手機巷帝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跑揉,“玉大人锅睛,你說我怎么就攤上這事±” “怎么了现拒?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長望侈。 經(jīng)常有香客問我印蔬,道長,這世上最難降的妖魔是什么脱衙? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任侥猬,我火速辦了婚禮例驹,結果婚禮上,老公的妹妹穿的比我還像新娘退唠。我一直安慰自己鹃锈,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布瞧预。 她就那樣靜靜地躺著屎债,像睡著了一般。 火紅的嫁衣襯著肌膚如雪垢油。 梳的紋絲不亂的頭發(fā)上盆驹,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音滩愁,去河邊找鬼躯喇。 笑死,一個胖子當著我的面吹牛硝枉,可吹牛的內容都是我干的廉丽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼檀咙,長吁一口氣:“原來是場噩夢啊……” “哼雅倒!你這毒婦竟也來了?” 一聲冷哼從身側響起弧可,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤蔑匣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棕诵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裁良,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年校套,在試婚紗的時候發(fā)現(xiàn)自己被綠了价脾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡笛匙,死狀恐怖侨把,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情妹孙,我是刑警寧澤秋柄,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站蠢正,受9級特大地震影響骇笔,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一笨触、第九天 我趴在偏房一處隱蔽的房頂上張望懦傍。 院中可真熱鬧,春花似錦芦劣、人聲如沸粗俱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽源梭。三九已至,卻和暖如春稍味,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背荠卷。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工模庐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人油宜。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓掂碱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親慎冤。 傳聞我的和親對象是個殘疾皇子疼燥,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容

  • 單例模式(SingletonPattern)一般被認為是最簡單、最易理解的設計模式蚁堤,也因為它的簡潔易懂醉者,是項目中最...
    成熱了閱讀 4,227評論 4 34
  • 1 單例模式的動機 對于一個軟件系統(tǒng)的某些類而言,我們無須創(chuàng)建多個實例披诗。舉個大家都熟知的例子——Windows任務...
    justCode_閱讀 1,431評論 2 9
  • 1 場景問題# 1.1 讀取配置文件的內容## 考慮這樣一個應用撬即,讀取配置文件的內容。 很多應用項目呈队,都有與應用相...
    七寸知架構閱讀 6,658評論 12 68
  • 1.單例模式概述 (1)引言 單例模式是應用最廣的模式之一剥槐,也是23種設計模式中最基本的一個。本文旨在總結通過Ja...
    曹豐斌閱讀 2,870評論 6 47
  • 2017年2月26日打卡 周日宪摧,晴好粒竖,有微風。 昨天下午接小玫瑰放學几于,趁空兒去了趟大超市蕊苗,買了幾個雞腿,準備做大盤...
    沈曼柔閱讀 251評論 2 2