Ba ngữ cảnh, cùng ý "không thể đổi" — nhưng "đổi" gì thì phụ thuộc:
java
final class String { ... } // 1. class — không extend được
class Base {
final void render() { ... } // 2. method — subclass không override được
}
final int MAX = 100; // 3. variable — không gán lại được
final List<String> names = new ArrayList<>();
names.add("Ada"); // OK — reference không đổi, NỘI DUNG vẫn đổi được
names = new ArrayList<>(); // ❌ compile errorfinal class— chống extends (vdString,Integer). Bảo vệ invariant + cho JIT inline mạnh hơn.final method— chống override. Cho template method khung không cho phép thay đổi.final variable— gán đúng 1 lần. Field phải gán ở khai báo/constructor.static final= hằng số (UPPERCASE).
Bẫy: final trên reference chỉ khoá biến — object bên trong vẫn mutate được. Muốn bất biến thật, dùng List.copyOf(...).
Liên quan: record field ngầm là final; sealed (Java 17+) chặt hơn final cho hierarchy có giới hạn subtype.
Three contexts, one idea: "cannot change" — but what cannot change depends on the context.
java
final class String { ... } // 1. class — cannot be extended
class Base {
final void render() { ... } // 2. method — subclasses cannot override
}
final int MAX = 100; // 3. variable — cannot be reassigned
final List<String> names = new ArrayList<>();
names.add("Ada"); // OK — reference fixed, CONTENT still mutable
names = new ArrayList<>(); // ❌ compile errorfinal class— prevents extension (e.g.String,Integer). Protects invariants + lets the JIT inline more aggressively.final method— prevents override. Used for template-method skeletons that must not change.final variable— assigned exactly once. Fields must be assigned at declaration or in a constructor.static final= constant (UPPERCASE).
Pitfall: final on a reference only locks the variable — the referenced object can still be mutated. For true immutability, use List.copyOf(...).
Related: record fields are implicitly final; sealed (Java 17+) is stricter than final for hierarchies with a limited set of subtypes.