引用可变对象时如何实现Java不可变类?及Company类有效性验证
嗨,咱们一步步来解决你的两个Java不可变性问题吧——这些都是设计不可变类时很常见的场景,问得非常好!
问题1:当类引用可变对象时,如何使其成为不可变类?
要让包含可变对象引用的类成为真正的不可变类,核心是彻底切断外部对内部可变对象的修改路径,具体要做到以下几点:
- 把类标记为
final:防止子类继承后通过重写方法破坏原有的不可变性规则 - 所有成员变量用
final修饰:保证成员变量的引用不会被重新赋值,确保对象状态初始化后就不会被替换 - 构造方法中做防御性拷贝:不要直接接收外部传入的可变对象引用,而是创建它的副本。这样外部修改原对象时,不会影响类内部的状态
- getter方法返回可变对象的副本:不要直接返回内部的可变对象引用,而是返回拷贝后的对象。避免外部通过getter拿到引用后,直接修改内部的可变对象
- 移除所有修改状态的方法:比如setter方法,确保没有任何公开方法能改变类的内部状态
问题2:当前Company类的实现是否能使其成为有效不可变类?
先回顾一下给出的可变Employee类代码:
public class Employee { private String empName; private int empId; public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public int getEmpId() { return empId; } public void setEmpId(int empId) { this.empId = empId; } }
当前的Company类不能成为有效的不可变类,有两个关键漏洞:
构造方法未做防御性拷贝:当外部传入一个
Employee对象后,外部仍然持有该对象的引用。如果外部调用setEmpName或setEmpId修改这个对象的属性,Company内部的employee引用指向的是同一个对象,这会直接导致Company的内部状态被意外改变。getter方法直接返回可变对象引用:调用
getEmployee()会拿到Company内部的employee引用,外部代码可以通过这个引用直接修改Employee的属性,同样会破坏Company的不可变性。
修复后的Company类实现
要让Company成为真正的不可变类,我们需要补上这两个漏洞:
public final class Company { final String companyName; final Employee employee; // 构造方法中对传入的Employee做防御性拷贝 public Company(String companyName, Employee employee) { this.companyName = companyName; // 创建一个新的Employee对象,复制原对象的属性 this.employee = new Employee(); this.employee.setEmpName(employee.getEmpName()); this.employee.setEmpId(employee.getEmpId()); } public String getCompanyName() { return companyName; } // getter返回Employee的拷贝,而不是原引用 public Employee getEmployee() { Employee copy = new Employee(); copy.setEmpName(employee.getEmpName()); copy.setEmpId(employee.getEmpId()); return copy; } }
这样修改后,外部无论怎么操作传入的原Employee对象,或者通过getEmployee()拿到的对象,都不会影响Company内部持有的Employee状态,从而保证Company是一个有效的不可变类。
内容的提问来源于stack exchange,提问作者Sid
相关产品推荐
相关产品推荐

