final修饰引用类型变量仅保证引用不可变,即变量不能指向新对象,但可修改所指对象的内部状态;其本身不提供深度不可变性,需配合私有字段、无setter等手段实现真正不可变。

final 修饰引用类型变量,表示该变量的“引用不可变”,而非其指向的对象内容不可变。 换句话说,你不能让这个变量再指向另一个对象,但可以修改它所指向对象的内部状态(前提是该对象本身不是不可变的)。
引用不可变:不能再赋新值
一旦用 final 声明了引用变量,并初始化完成,就无法再把它指向其他对象:
- final List<String> list = new ArrayList<>();
- list = new LinkedList<>(); // 编译错误!
- list.add("hello"); // 合法!对象内容可变
对象内容是否可变,取决于对象自身
final 不影响对象内部字段是否能被修改。例如:
- final StringBuilder sb = new StringBuilder("a");
- sb.append("b"); // 合法,StringBuilder 是可变类
- final String s = "abc";
- s.concat("d"); // 返回新字符串,但 s 仍指向原字符串,且 String 本身不可变
常见误区:误以为 final 能保证“深度不可变”
很多人以为加了 final 就等于整个对象树都锁死了,其实不是:
立即学习“Java免费学习笔记(深入)”;
- final Person p = new Person();
- p.name = "Alice"; // 合法(若 name 是 public 字段)
- p.setAge(30); // 合法(若提供 setter 方法)
- 要真正实现不可变,需组合使用:final 字段 + 私有字段 + 无 setter + 构造器初始化 + 防御性拷贝(如返回集合副本)
什么时候该用 final 引用?
主要价值在于明确语义和辅助安全:
- 方法参数加 final,表明该方法不会重新赋值给它(提升可读性,部分 IDE 会提示)
- 局部变量加 final,便于在匿名内部类或 lambda 中访问(Java 8+ 要求“有效 final”)
- 成员变量加 final,配合私有性和构造器,是构建不可变类的第一步










