static 成員屬於類,非 static 成員屬於實例。 這是理解所有差異的根本。
| 維度 | static 變量/方法 | 實例變量/方法 |
|---|---|---|
| 內存區域 | 方法區(Metaspace,JDK8+),隨類加載一次分配 | 堆,每 new 一次對象分配一次 |
| 生命週期 | 類加載 → 類卸載(通常伴隨 JVM 結束) | 對象創建 → GC 回收 |
| 存在份數 | 全局唯一份,所有實例共享 | 每個實例一份,相互獨立 |
| 初始化時機 | 類加載階段(<clinit>),靜態代碼塊、靜態字段賦值 | 對象實例化階段(<init>),構造器、實例代碼塊、字段賦值 |
public class Demo {
static int staticVar = 10;
int instanceVar = 20;
static void staticMethod() { System.out.println("靜態方法"); }
void instanceMethod() { System.out.println("實例方法"); }
}
// 調用
Demo.staticMethod(); // ✅ 推薦:類名調用
Demo.staticVar = 100; // ✅ 推薦:類名訪問
Demo demo = new Demo();
demo.instanceMethod(); // ✅ 必須:實例調用
demo.instanceVar = 200; // ✅ 必須:實例訪問
// ⚠️ 雖然實例也能調用 static,但會有警告,不推薦
demo.staticMethod(); // 編譯器警告:"The static method should be accessed in a static way"
demo.staticVar = 300; // 同理
invokestatic:調用靜態方法,操作數棧無 this,直接按類名解析方法符號引用。invokevirtual:調用實例方法,操作數棧頂需有對象引用 this,支持多態動態分派。getstatic/putstatic,實例字段用 getfield/putfield(需對象引用)。因此:靜態方法內不能直接用 this、super,不能調用非靜態成員(因無實例上下文)。
Math、Collections、StringUtils,無狀態、無副作用。public static final int MAX = 100;,編譯期常量折疊,性能最優。AtomicInteger/synchronized/ThreadLocal。