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

一、靜態內部類(靜態嵌套類)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保證了一個類的 初始化在多執行緒下被同步加鎖)