final修饰变量只锁住引用不可再赋值,不保证对象内容不可变;用于方法表示不可重写但可重载;用于类表示不可继承;final字段需在构造完成前安全初始化以保障线程可见性。
final修饰变量时,到底锁住了什么
很多人以为final让变量“不可变”,其实它只保证**引用不可再赋值**,不等于对象内容不可变。比如final List list = new ArrayList();之后,你不能写list = new ArrayList();(编译报错),但list.add("a")完全合法。
常见错误现象:
• 用final Map存配置,运行时被意外修改,误以为安全
• 单元测试里反复add()同一个final集合,结果前一个测试污染后一个
- 若需真正不可变容器,用
Collections.unmodifiableList()或ImmutableList.of()(Guava) - 对自定义类,
final字段 + 私有构造 + 不暴露可变内部状态,才是完整不可变设计 - 基本类型(
int、boolean)用final确实等效于常量,JVM可能内联优化
final方法为什么不能被重写,但能被重载
final加在方法上,是告诉编译器“这个行为不允许子类改变”。它不影响重载(overload),只阻止重写(override)。比如父类有final void log(String msg),子类可以新增void log(String msg, int level),但不能写@Override void log(String msg)。
使用场景:
• 模板方法模式中,templateMethod()设为final,强制子类只实现钩子方法
• 工具类中关键校验逻辑(如validateInput()),防止下游绕过安全检查
立即学习“Java免费学习笔记(深入)”;
- 性能影响极小:现代JVM对
final方法可能做去虚化(devirtualization),但别为此刻意加final - 注意IDE警告:如果一个
final方法从未被继承,加final只是增加维护噪音 - 接口里不能用
final方法(Java 8+允许default和static,但final仍非法)
final类的继承限制与真实用途
声明final class StringUtils,意味着它既不能被继承,也不能被代理(除非用字节码工具)。这不是为了“防止别人扩展”,而是明确表达“这个类的设计边界已封闭”。String、Integer、LocalDateTime都是典型例子。