首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java static 修飾符詳解:靜態成員、靜態代碼塊、初始化順序與單例模式

     編輯:Java 相關知識

static 核心語義:屬於類,不屬於實例

static 修飾的成員屬於類級別,類加載時初始化,全類共享單份存儲。非靜態成員屬於實例級別,每個對象獨立一份。

靜態變量(類變量)

內存模型對比

// 非靜態:每個對象獨立存儲
class Box { int l, w, h; }
Box a = new Box(10,20,30);
Box b = new Box(40,20,10);
// 堆中:a.l=10, a.w=20...  b.l=40, b.w=20...  互不干擾

// 靜態:所有對象共享同一地址
class StaticDemo { static int m; int n; }
StaticDemo s1 = new StaticDemo();
StaticDemo s2 = new StaticDemo();
s1.m = 100;
System.out.println(s2.m);  // 100 (共享)
// 方法區/元空間:StaticDemo.m = 100

適用場景

  • 共享數據:計數器、緩存、配置、單例實例。
  • 常量定義:public static final(配合 final 內聯優化)。
  • 便捷訪問:ClassName.field 無需創建對象。

訪問語法

// 推薦:類名訪問
StaticDemo.m = 10;
int x = StaticDemo.m;

// 不推薦:對象訪問(編譯器轉為類名,誤導閱讀者)
StaticDemo obj = new StaticDemo();
int y = obj.m;  // 警告:static member accessed via instance

靜態方法(類方法)

  • 無 this,不能直接訪問非靜態成員(字段/方法)。
  • 可直接訪問靜態成員。
  • 常用於工具類、工廠方法、單例獲取、無狀態邏輯。

標準工具類模板

public final class MathUtils {
    private MathUtils() {}  // 防實例化
    
    public static int max(int a, int b) {
        return a > b ? a : b;
    }
    
    public static double sqrt(double x) {
        return Math.sqrt(x);  // 委託 JDK
    }
}

// 調用
int m = MathUtils.max(10, 20);  // 無需 new

靜態代碼塊:類級初始化邏輯

public class DatabaseConfig {
    static final String URL;
    static final String USER;
    static final String PASS;
    
    static {  // 類加載時執行一次
        try (InputStream is = DatabaseConfig.class.getResourceAsStream("/db.properties")) {
            Properties p = new Properties();
            p.load(is);
            URL = p.getProperty("url");
            USER = p.getProperty("user");
            PASS = p.getProperty("pass");
        } catch (IOException e) {
            throw new ExceptionInInitializerError(e);  // 包裝為 Error
        }
    }
}
  • 類加載階段(Class.forName、首次 new、首次訪問靜態成員)執行一次。
  • 按源碼順序執行多個靜態塊/靜態字段初始化。
  • 異常必須捕獲或拋 ExceptionInInitializerError(受檢異常不可拋出)。

完整初始化順序(核心面試點)

// 父類靜態 → 子類靜態 → 父類實例 → 父構造 → 子類實例 → 子構造

class Parent {
    static { System.out.println("P-static"); }
    { System.out.println("P-instance"); }
    public Parent() { System.out.println("P-ctor"); }
}

class Child extends Parent {
    static { System.out.println("C-static"); }
    { System.out.println("C-instance"); }
    public Child() { System.out.println("C-ctor"); }
}

public class Test {
    public static void main(String[] args) {
        new Child();
    }
}

/* 輸出:
P-static
C-static
P-instance
P-ctor
C-instance
C-ctor
*/

關鍵點

  1. 靜態初始化:父→子,各類內部按聲明順序。
  2. 實例初始化:父類實例塊/構造 → 子類實例塊/構造。
  3. 實例初始化塊 {...} 在構造器之前執行,每次 new 都執行。
  4. super() 隱式調用父類無參構造器,觸發父類實例初始化。

單例模式:static 經典應用

1. 餓漢式(類加載初始化,線程安全)

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

2. 懶漢式雙重檢查鎖(JDK 5+ volatile 保證可見性)

public final class Singleton {
    private static volatile Singleton INSTANCE;
    private Singleton() {}
    public static Singleton getInstance() {
        if (INSTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) INSTANCE = new Singleton();
            }
        }
        return INSTANCE;
    }
}

3. 靜態內部類(推薦:延遲加載+線程安全+簡潔)

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

4. 枚舉單例(最強:防反射/序列化破壞)

public enum Singleton {
    INSTANCE;
    public void doSomething() {}
}

static 導入(JDK 5+)

import static java.lang.Math.*;   // 導入所有靜態成員
import static java.lang.Math.PI;  // 導入單個

// 直接使用
double r = sqrt(2);  // 無需 Math.sqrt
double area = PI * r * r;
  • 提高可讀性(常量/工具方法頻繁使用時)。
  • 濫用導致命名空間污染、來源不明,慎用。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved