面試總結系列——單例模式靜態內部類

前言:

仔細思考了一下這個模式,往裏面深挖了一下,發現關於靜態內部類未知的太多。尤其是java虛擬機classloader加載機制一臉迷茫,所以決定記錄一下。下面相關問題的解答我都會給出推薦的博客,因爲我自己再寫不敢保證比他們寫的更好。再次膜拜大神。

今天看單例模式,仔細思考了下靜態內部類的單例。
關於單例模式的講解,推薦一篇博文,可以說單例模式是多線程入門的教程。
博文地址
博文上面講解的很清楚,就不多說了。原文中作者有這樣一句話

第3種,利用了classloader的機制來保證初始化instance時只有一個線程,所以也是線程安全的,同時沒有性能損耗,所以一般我傾向於使用這一種。

那麼,什麼是classloader機制?爲什麼保證了線程安全?這個問題先留着,我們先看下文中的靜態單例模式。

public class Singleton {    
    private static class LazyHolder {    
       private static final Singleton INSTANCE = new Singleton();    
    }    
    private Singleton (){}    
    public static final Singleton getInstance() {    
       return LazyHolder.INSTANCE;    
    }    
}    

這裏是如何實現餓漢式的?在印象中,靜態內部類難道不是一開始就加載嗎?一開始就實現了INSTANCE = new Singleton()?那麼哪裏來的餓漢模式?
查閱資料發現(博文參考資料)如下的幾句話:

  • 類級內部類指的是,有static修飾的成員內部類。如果沒有static修飾的成員式內部類被稱爲對象級內部類。
  • 類級內部類相當於其外部類的static成分,它的對象與外部類對象間不存在依賴關係,因此可以直接創建。而對象級內部類的實例,是綁定在外部對象實例中的。

那麼靜態內部類是什麼時候加載的呢?
參考博文1
文中講述類加載機制:
類初始化的時機,有且僅有四個:

  1. 遇到new、getstatic、putstatic、invokestatic這四條字節碼指令的時候。
  2. 使用java.lang.reflect進行反射調用的時候。
  3. 當初始化一個類的時候,發現其父類還沒有初始化,那麼先去初始化它的父類。
  4. 當虛擬機啓動的時候,需要初始化main函數所在的類。

內部類(不論是靜態內部類還是非靜態內部類)都是在第一次使用時纔會被加載。
對於非靜態內部類是不能出現靜態模塊(包含靜態塊,靜態屬性,靜態方法等)
非靜態類的使用需要依賴於外部類的對象

參考博文2(關於這個問題,這一篇博文解釋足夠詳細了)
原文講述如下:
虛擬機規範則嚴格規定了有且只有四種情況必須立即對類進行初始化,遇到new、getStatic、putStatic或invokeStatic這4條字節碼指令時,如果類沒有進行過初始化,則需要先觸發其初始化。
生成這4條指令最常見的java代碼場景是:
1) 使用new關鍵字實例化對象
2) 讀取一個類的靜態字段(被final修飾、已在編譯期把結果放在常量池的靜態字段除外)
3) 設置一個類的靜態字段(被final修飾、已在編譯期把結果放在常量池的靜態字段除外)
4) 調用一個類的靜態方法

靜態內部類其實和外部類的靜態變量,靜態方法一樣,只要被調用了都會讓外部類的被加載。不過當只調用外部類的靜態變量,靜態方法時,是不會讓靜態內部類的被加載

關於類加載時機

參考博文1

參考博文2:強薦這篇博文,知識點深淺剛好合適,裏面的問題,確實我之前沒遇到過,長見識了。

說道類加載時機,不得不提的一個重要的面試題就是,new 一個子類代碼時的執行順序。
參考博文(雖然這篇博文作者也標明轉載)

這裏直接給出結論吧,方便記憶.

  1. 父類–靜態變量
  2. 父類–靜態初始化塊
  3. 子類–靜態變量
  4. 子類–靜態初始化塊
  5. 父類–變量
  6. 父類–初始化塊
  7. 父類–構造器
  8. 子類–變量
  9. 子類–初始化塊
  10. 子類–構造器

類加載時機我個人覺得是個難點,這一塊必須多花功夫看看博客。本弱也在學習中,學好之後再來更新下這篇博文.

疑問

其實,涉及到volatile還有一個問題,大家都知道,一般雙從鎖定的單例都會涉及到重排序的問題,但是,synch指令其實也有內存回刷的功能,這一點其實蠻重要,大家可以仔細是靠下,爲啥有了synch還是需要volatile,晚點再來解答。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章