final修饰变量仅保证引用不可变而非对象不可变;修饰方法禁止重写但允许重载;修饰类禁止继承且隐含所有方法final;final是不可变的必要非充分条件,需配合深拷贝和不可变视图。

final修饰变量:值不可变 ≠ 对象不可变
声明为 final 的变量只能赋值一次,但若其类型是引用类型(如 ArrayList、StringBuilder),变量本身不可重新指向其他对象,而对象内部状态仍可修改。
-
final List→ 合法:可执行list = new ArrayList(); list.add("a") -
list = new ArrayList();→ 编译错误:不能重新赋值 - 若需真正不可变容器,应使用
Collections.unmodifiableList()或List.of()(Java 9+)
final修饰方法:禁止子类重写,但不影响重载
final 方法在运行时不会被动态绑定覆盖,JVM 可能对其内联优化;它不阻止同名不同参的重载,也不影响静态分派逻辑。
- 子类中定义
void foo(int x)和父类final void foo(String s)是允许的 - 子类尝试
@Override void foo(String s)会触发编译错误:Cannot override the final method from Parent - 常见误用:在抽象类中把模板方法设为
final,却忘了把钩子方法(hook method)留为protected非 final
final修饰类:彻底关闭继承链
类被声明为 final 后,任何 extends 尝试都会在编译期报错;这也隐含意味着该类所有方法自动成为 final(即使没显式写),但字段仍可按需声明为 final 或非 final。
-
final class StringUtils { ... }→class MyUtils extends StringUtils编译失败 -
标准库中
String、Integer、LocalDateTime均为final类,这是不可变性的基础保障 - 注意:
final类仍可实现接口,也可被依赖注入框架代理(如 CGLIB 无法继承,但可用 JDK 动态代理接口)
不可变设计中 final 的真实作用边界
final 是不可变(immutability)的必要非充分条件。它只约束“引用不可变”或“结构不可扩展”,不保证深层状态安全。
立即学习“Java免费学习笔记(深入)”;
- 构造器中未防御性拷贝可变参数(如传入外部
new Date())→ 外部仍可修改该对象,破坏不可变性 - 字段为
final但类型是可变集合,且 getter 直接返回原始引用 → 调用方拿到后可随意修改 - 正确做法:字段
final+ 构造器深拷贝 + getter 返回不可变视图(如Collections.unmodifiableXXX)
public final class Config {
private final Map props;
public Config(Map input) {
// 错误:props = input;
this.props = Collections.unmodifiableMap(new HashMap<>(input));
}
public Map getProps() {
return props; // 安全:不可修改副本
}
}
很多人卡在“用了 final 就等于不可变”这层直觉上——其实 final 只锁住了引用和继承路径,真正的不可变需要整条构造与访问链都配合防御策略。










