为何将类设为final以创建不可变对象?析代码类型转换与属性变更
嘿,我来帮你拆解这两个Java问题,都是基础但容易踩坑的点:
你的两个Java疑问解答
疑问1:为啥把类设为final才能做不可变对象?
不可变对象的核心是「一旦创建完成,内部状态就再也无法被修改」。把类标记为final,最关键的原因是防止子类破坏不可变性约定:
- 如果类不是final,其他开发者可以编写子类继承它,重写父类的方法——比如父类的getter本来只返回固定值,子类能偷偷改成返回可变引用,或者在方法里悄悄修改内部状态;
- 子类还能新增字段和setter方法,直接修改对象状态,让「不可变」的约定彻底失效。
举个例子:如果你的immutable类没设final,我写个TrickyChild继承它,加个setTemp方法,那这个子类的对象就完全可变了,而如果父类是final,就能从根源上杜绝这种操作。
顺便提一句,创建真正的不可变对象除了类设final,还要注意:
- 所有字段用
private final修饰; - 不提供任何修改字段的方法(比如setter);
- 如果字段是引用类型,要确保引用的对象本身也不可变,或者返回时返回副本,避免外部能修改内部状态。
疑问2:代码里的强制转换和值被修改的原因
首先我把你没写完的代码补全了(根据输出行为合理完善的版本),方便理解:
public class HelloWorld{ public static void main(String []args){ child c = new child(4); System.out.println(c.getTemp()); // line #4 prints 4 immutable i = (immutable) c; //line #5 System.out.println(i.getTemp()); // line #6 prints 4 c.setTemp(10); //line #7 System.out.println(i.getTemp()); // line 8 prints 10 } } class immutable{ private int tmp; public immutable(int tmp) { this.tmp = tmp; } public int getTemp() { return tmp; } } class child extends immutable { private int tmp; public child(int tmp) { super(tmp); this.tmp = tmp; } public void setTemp(int tmp) { this.tmp = tmp; } @Override public int getTemp() { return tmp; } }
第5行的强制类型转换到底在干啥?
这行其实是多余但合法的向上转型:child是immutable的子类,子类对象本来就可以直接赋值给父类引用(比如直接写immutable i = c;完全没问题)。这个强制转换只是在跟编译器说:「我确定这个c是immutable类型(或者它的子类),你别报错」。但运行时,i指向的还是原来那个child对象,既没有创建新对象,也没有改变对象本身的类型。
为啥第7行改了c的tmp,i.getTemp()也变了?
这是Java多态特性导致的:
- 虽然
i的声明类型是immutable,但它实际指向的是一个child对象; - 当调用
i.getTemp()时,Java会根据对象的实际类型(也就是child),调用子类重写的getTemp()方法——这个方法返回的是child自己的tmp字段; - 第7行
c.setTemp(10)修改的就是这个child对象的tmp字段,所以后续i.getTemp()自然会返回修改后的值10。
另外还要吐槽一句:你的immutable类根本不是真正的不可变类!因为它没设final,允许子类继承,子类还能加setter修改状态——这正好呼应了第一个问题的答案,要做真正的不可变类,类必须设final,不然很容易被子类破坏。
内容的提问来源于stack exchange,提问作者uideveloperui
相关产品推荐
相关产品推荐

