靜態內部類實現的單例模式是執行緒安全的

little_mao發表於2021-04-18

一、靜態內部類(靜態巢狀類)vs非靜態內部類(內部類)

靜態內部類

*靜態內部類只能訪問外部類的靜態方法和靜態屬性,如果是private也能訪問,其他則不能訪問,建立物件不依賴外部類
*靜態內部類可以定義靜態的屬性和方法

非靜態內部類

  • 內部類可以訪問其所在類的屬性(包括所在類的私有屬性),內部類建立自身物件需要先建立其所在類的物件
  • 可以定義內部介面,且可以定義另外一個內部類實現這個內部介面
  • 內部類不能定義static元素
  • 內部類可以多巢狀

總結

靜態內部類和外部類是相互獨立的,建立例項或者建立什麼型別的物件都不受限制
非靜態內部類是外部類的一部分,建立例項必須先建立外部類的例項,可以訪問外部類的所有屬性

二、類的初始化及物件建立

類的載入、連結、初始化

1.class檔案(二進位制)通過類的載入器(引導類載入器、自定義載入器)載入(雙親委派機制)到記憶體中,並建立java.lang.Class物件(類是一類事物的抽象,Class是類的抽象,抽象的抽象)
2.連結:
①驗證:驗證位元組碼檔案格式等是否正確
②準備:類的靜態變數分配記憶體,並設定預設值
③解析:符號引用轉換為直接引用
3.初始化
初始化階段是執行類構造器()方法的過程。()方法是由編譯器自動收集類中的所有類變數的賦值動作和靜態語句塊static{}中的語句合併產生的,編譯器收集的順序是由語句在原始檔中出現的順序所決定的,靜態語句塊只能訪問到定義在靜態語句塊之前的變數,定義在它之後的變數,在前面的靜態語句塊可以賦值,但是不能訪問

類例項化的時機

1.使用new關鍵字建立物件
2.使用Class類的newInstance方法(反射機制)
3.使用Constructor類的newInstance方法(反射機制)
4.使用Clone方法建立物件
5.使用(反)序列化機制建立物件

類例項化的過程

static final 變數編譯階段分配記憶體空間並賦值→父類的類構造器() -> 子類的類構造器() -> 父類的成員變數和例項程式碼塊 -> 父類的建構函式 -> 子類的成員變數和例項程式碼塊 -> 子類的建構函式。

三、靜態內部類建立單例物件怎麼保證執行緒安全

package com.bo.singleton;
/*靜態內部類建立單例物件*/
public class StaticInnerTest {
    public StaticInnerTest() {
        System.out.println("靜態內部類無參建構函式");
    }

    public static StaticInnerTest getInstance() {
        return Inner.sit;
    }
    //方法不需要設定同步
    public static class Inner{
        private static final StaticInnerTest sit = new StaticInnerTest();
    }

    public static void main(String[] args) {
        StaticInnerTest s1 = StaticInnerTest.getInstance();
        StaticInnerTest s2 = StaticInnerTest.getInstance();
        System.out.println(s1==s2);
    }
}

靜態內部類的特點:外部類載入時不需要載入靜態內部類,不被載入則不佔用記憶體,(延遲載入)當外部類呼叫getInstance方法時,才載入靜態內部類,靜態屬性保證了全域性唯一,靜態變數初始化保證了執行緒安全,所以這裡的方法沒有加synchronized關鍵字(JVM保證了一個類的 初始化在多執行緒下被同步加鎖)

相關文章