Java static 關鍵字

static 表示屬於類別而非物件,所有實例共享。

靜態變數

public class Counter {
    private static int count = 0;  // 靜態變數,所有物件共享
    private int id;                // 實例變數,每個物件各自擁有
    
    public Counter() {
        count++;
        this.id = count;
    }
    
    public static int getCount() {
        return count;
    }
    
    public int getId() {
        return id;
    }
}

Counter c1 = new Counter();  // count=1, id=1
Counter c2 = new Counter();  // count=2, id=2
Counter c3 = new Counter();  // count=3, id=3

System.out.println(Counter.getCount());  // 3

靜態方法

靜態方法屬於類別,可以直接用類別名稱呼叫:

public class MathUtils {
    public static int add(int a, int b) {
        return a + b;
    }
    
    public static int max(int a, int b) {
        return (a > b) ? a : b;
    }
}

// 使用類別名稱呼叫
int sum = MathUtils.add(5, 3);  // 8
int max = MathUtils.max(10, 20);  // 20

靜態方法的限制

靜態方法不能存取實例變數和實例方法:

public class Example {
    private int value = 10;         // 實例變數
    private static int count = 0;   // 靜態變數
    
    public static void staticMethod() {
        // System.out.println(value);  // 錯誤!
        System.out.println(count);     // OK
        
        // instanceMethod();  // 錯誤!
        anotherStatic();     // OK
    }
    
    public void instanceMethod() {
        System.out.println(value);  // OK
        System.out.println(count);  // OK(可以存取靜態)
    }
    
    public static void anotherStatic() {
        // ...
    }
}

靜態常數

public class Constants {
    public static final double PI = 3.14159;
    public static final int MAX_SIZE = 100;
    public static final String APP_NAME = "MyApp";
}

// 使用
double area = Constants.PI * radius * radius;

靜態區塊

用於初始化靜態變數:

public class DatabaseConfig {
    private static String url;
    private static String username;
    
    // 靜態區塊,類別載入時執行一次
    static {
        System.out.println("載入設定...");
        url = "jdbc:mysql://localhost:3306/db";
        username = "admin";
    }
    
    public static String getUrl() {
        return url;
    }
}

靜態內部類別

public class Outer {
    private static int outerStatic = 10;
    private int outerInstance = 20;
    
    // 靜態內部類別
    public static class Inner {
        public void print() {
            System.out.println(outerStatic);  // OK
            // System.out.println(outerInstance);  // 錯誤!
        }
    }
}

// 使用
Outer.Inner inner = new Outer.Inner();
inner.print();

靜態 import

可以直接使用靜態成員而不需要類別名稱:

import static java.lang.Math.PI;
import static java.lang.Math.sqrt;

public class Circle {
    public double getArea(double radius) {
        return PI * radius * radius;  // 不需要 Math.PI
    }
    
    public double getDiagonal(double a, double b) {
        return sqrt(a * a + b * b);  // 不需要 Math.sqrt
    }
}

實際應用

工具類別

public class StringUtils {
    private StringUtils() {}  // 私有建構子
    
    public static boolean isEmpty(String s) {
        return s == null || s.isEmpty();
    }
    
    public static String capitalize(String s) {
        if (isEmpty(s)) return s;
        return Character.toUpperCase(s.charAt(0)) + s.substring(1);
    }
}

單例模式

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

計數器

public class User {
    private static int totalUsers = 0;
    private int userId;
    private String name;
    
    public User(String name) {
        totalUsers++;
        this.userId = totalUsers;
        this.name = name;
    }
    
    public static int getTotalUsers() {
        return totalUsers;
    }
}

靜態 vs 實例

特性靜態實例
屬於類別物件
記憶體一份每個物件一份
存取方式類別.成員物件.成員
使用 this不可以可以
存取實例成員不可以可以

何時使用 static

  • 工具方法(不需要物件狀態)
  • 常數
  • 工廠方法
  • 計數器或共享資料
  • main 方法