Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Java

Sự khác biệt giữa biến static và non-static trong Java

Biến (field) trong Java được phân loại thành static (class variable) và non-static / instance variable tùy thuộc vào từ khóa static.

Static Variable (Biến lớp / Class Variable)

  • Khai báo với từ khóa static.
  • Thuộc về class, không thuộc instance nào.
  • Chỉ có một bản sao (single copy) chung cho tất cả instance.
  • Khởi tạo khi class được load (class loading), trước khi tạo bất kỳ object nào.
  • Truy cập qua ClassName.staticField (khuyến khích) hoặc instance.staticField (có warning).
  • Đời sống = đời sống của class (cho đến khi class unload).

Non-Static Variable (Instance Variable / Biến thể hiện)

  • Không có từ khóa static.
  • Thuộc về instance (object) cụ thể.
  • Mỗi new ClassName() tạo ra bản sao riêng của biến này.
  • Khởi tạo khi object được tạo (sau constructor).
  • Chỉ truy cập qua instance.field.
  • Đời sống = đời sống của object (được GC khi object không còn tham chiếu).

Bảng so sánh

STTTiêu chíStatic VariableNon-Static Variable
1 Truy cập Từ static method, non-static method, static block, instance method. Chỉ từ instance method, constructor, instance block. Không thể truy cập trực tiếp từ static context.
2 Chia sẻ (Sharing) Chia sẻ cho tất cả instance - thay đổi ở đâu thấy ở đâu. Riêng biệt cho mỗi instance.
3 Cấp phát bộ nhớ Một lần ở Metaspace/Heap (class metadata). Mỗi lần new object (Heap).
4 Từ khóa Bắt buộc static. Không cần từ khóa đặc biệt.
5 Khởi tạo Static initializer block: static { ... }. Instance initializer block: { ... } hoặc constructor.
6 Serialization Không được serialize (transient mặc định). Được serialize mặc định.

Ví dụ minh họa

public class JavaTester {
    // Instance variable
    public int counter = 0;
    
    // Static variable
    public static int staticCounter = 0;
    
    public JavaTester() {
        counter++;       // Mỗi instance tăng counter riêng
        staticCounter++; // Tất cả instance cùng tăng staticCounter
    }
    
    public static void main(String args[]) {
        JavaTester t1 = new JavaTester();
        JavaTester t2 = new JavaTester();
        JavaTester t3 = new JavaTester();
        
        // counter là instance variable -> mỗi object có bản sao riêng
        System.out.println("t1.counter: " + t1.counter); // 1
        System.out.println("t2.counter: " + t2.counter); // 1
        System.out.println("t3.counter: " + t3.counter); // 1
        
        // staticCounter là class variable -> chung
        System.out.println("staticCounter (qua t3): " + t3.staticCounter); // 3
        System.out.println("staticCounter (qua class): " + JavaTester.staticCounter); // 3
    }
}

Kết quả

t1.counter: 1
t2.counter: 1
t3.counter: 1
staticCounter (qua t3): 3
staticCounter (qua class): 3

Lỗi thường gặp

public class ErrorDemo {
    int instanceVar = 10;
    static int staticVar = 20;
    
    static void staticMethod() {
        // System.out.println(instanceVar); // COMPILE ERROR: non-static variable cannot be referenced from static context
        System.out.println(staticVar);     // OK
    }
    
    void instanceMethod() {
        System.out.println(instanceVar); // OK
        System.out.println(staticVar);   // OK
    }
}

Best Practices

  • Hằng số (constants): static final (UPPER_SNAKE_CASE). Ví dụ: static final double PI = 3.14159;
  • Shared state: Dùng static cẩn thận (thread-safety, testing khó). Cân nhắc Dependency Injection.
  • Singleton pattern: Static field hold instance.
  • Utility class: Chỉ static method/field, private constructor.
  • Tránh mutable static field trong multi-threaded env trừ khi synchronized/atomic.

Memory Model (JVM)

  • Static variables: Lưu trong Metaspace (Java 8+) / PermGen (Java 7-), một phần của Heap cho class metadata.
  • Instance variables: Lưu trong Heap như một phần của object.
  • Local variables (trong method): Lưu trong Stack (frame của thread).