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

Khác biệt giữa Object Mutable (Đ可变) và Immutable (Bất biến) trong Java

Trong Java, object được phân loại theo khả năng thay đổi trạng thái (state) sau khi tạo:

Định nghĩa

  • Immutable Object: Trạng thái không thể thay đổi sau khi khởi tạo. Mọi trường (field) đều final, không có setter, không cho phép subclass ghi đè (class final).
  • Mutable Object: Trạng thái có thể thay đổi qua setter, method sửa đổi, hoặc truy cập field trực tiếp.

Bảng so sánh

Tiêu chíMutable ObjectImmutable Object
Thay đổi stateCó (setter, method sửa đổi)Không (chỉ getter, không setter)
Thread-safeKhông tự động (cần synchronized)Tự nhiên thread-safe (không race condition)
Class finalThường không finalNên khai báo final class
FieldKhông bắt buộc finalTất cả private final
Defensive copyKhông cầnCần cho field mutable (Date, List, array...)
Ví dụ JDKStringBuilder, ArrayList, Date, StringBufferString, Integer, Long, LocalDate, UUID

Ví dụ Immutable Class (Chuẩn)

public final class ImmutableStudent {
    private final String name;
    private final int age;
    private final List subjects; // Mutable object → cần defensive copy
    
    public ImmutableStudent(String name, int age, List subjects) {
        this.name = name;
        this.age = age;
        // Defensive copy: không chia sẻ reference với caller
        this.subjects = new ArrayList<>(subjects);
    }
    
    // Chỉ getter, KHÔNG setter
    public String getName() { return name; }
    public int getAge() { return age; }
    
    // Trả về defensive copy để bảo vệ internal state
    public List getSubjects() {
        return new ArrayList<>(subjects); // Hoặc Collections.unmodifiableList(subjects)
    }
    
    // "With-er" method: trả về instance mới với thay đổi (functional style)
    public ImmutableStudent withAge(int newAge) {
        return new ImmutableStudent(this.name, newAge, this.subjects);
    }
}

Ví dụ Mutable Class

public class MutableStudent {
    private String name;
    private int age;
    private List subjects = new ArrayList<>();
    
    public MutableStudent(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // Getter & Setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public List getSubjects() { return subjects; } // Trả về reference thật → caller có thể sửa!
    
    public void addSubject(String s) { subjects.add(s); }
}

Tại sao Immutable quan trọng?

  • Thread-safety: Dùng chung an toàn trong multi-thread không cần lock.
  • Dễ reasoning: State không bao giờ thay đổi → code dễ hiểu, debug.
  • Key của Map/Set: Chỉ immutable object an toàn làm key (hashCode/equals ổn định).
  • Caching/Pooling: Có thể reuse an toàn (String pool, Integer cache).
  • Failure atomicity: Nếu exception xảy ra trong constructor, object không bao giờ ở trạng thái invalid.

Lưu ý: Defensive Copy

Immutable class chứa field là object mutable (List, Date, Array, custom object) → phải copy khi nhận từ constructor và khi trả về getter. Nếu không, caller vẫn giữ reference và sửa đổi được internal state.