[英]Given a mutable class, how to make immutable a specific object of this class?
[英]How to make a class immutable when its referencing a mutable object?
假设我在Java中有一个名为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;
}
}
现在我想在一个不可变的类中使用这个对象,让我们说一个公司的格式如下。 而条件是我无法修改
public final class Company {
final String companyName;
final Employee employee;
public Company(String companyName, Employee employee) {
this.companyName = companyName;
this.employee = employee;
}
public String getCompanyName() {
return companyName;
}
public Employee getEmployee() {
return employee;
}
}
所以我的问题是,当我引用一个可以修改的内部对象时,这是使公司类不可变的有效方法吗?
在本文中引用https://www.journaldev.com/129/how-to-create-immutable-class-in-java在最终类的构造函数中深入克隆Employee对象。 这样您就不会使用对象引用。
我想到的两件事:
为您的Employee
添加一个只暴露getter的ReadOnlyEmployee
接口。 然后你必须将getEmployee()
的返回类型更改为ReadOnlyEmployee
。 该解决方案的优点在于它对用户来说清晰明了。 问题是getter返回的另一种类型比构造函数接受的类型可能令人困惑。
添加一个代理类,该类扩展了在setter调用时抛出IllegalAccessException
或类似的Employee
类。 优点是您不必引入新的接口或更改Company
的方法。 缺点是可能的运行时异常。
问题是您释放对员工实例的引用,因此调用者可以修改该对象。
您返回指向该员工副本的链接,并不再担心接下来会发生什么。 您保护了基础实例。 调用者可以使用副本执行他们想要的任何操作,而您的字段保持一致且实际上不变(事实上,它当然是可更改的)。
public class Employee { public Employee(Employee o) { // copy evething you need from o } } public final class Company { public Employee getEmployee() { return new Employee(employee); } }
问题在这里? 调用者正在改变员工的数据,无法弄清楚为什么公司内部没有任何变更。
您返回对Company
内部子类Employee
的引用。 在此类中,您可以覆盖setter和其他更改状态的方法。 例如,调用者在检索到的Employee
上调用此类修改方法时可能会收到UnsupportedOperationException
。
public final class Company { private final CompanyEmployee companyEmployee; public Company(String companyName, Employee employee) { this.companyName = companyName; companyEmployee = new CompanyEmploye(employee); } private static class CompanyEmployee extends Employee { public Employee(Employee o) { super(o); } public void setEmpName(String empName) { throw new UnsupportedOperationException(); } public void setEmpId(int empId) { throw new UnsupportedOperationException(); } } public Employee getEmployee() { return companyEmployee; } }
问题在这里? 继承用于控制访问。
否则,由可变组件的不可变类不是一成不变的。
当我引用可以修改的内部对象时,这是使
Company
类不可变的有效方法吗?
根据我的理解,从不可变类的实例获得的任何组件都不应该是可以改变的。 无论在何种级别,都可能发生变更请求。
从技术上讲,没有。 添加final
使引用不可变:您不能分配不同的Employee
对象。 this.employee = ...
是不可能的。
但是,终结性并不像C ++中的constness那样具有传染性。 仍然可以调用getEmployee().setEmpName(...)
或getEmployee().setEmpId(...)
并修改employee对象。 你不能用新的替换它,但你可以修改那里的对象。
如果您想使Company
完全不可变,那么您需要在两个地方制作Employee
对象的防御性副本。 一,您需要复制构造函数中传递的对象。 二,你需要从getEmployee()
返回一个副本,以防止暴露内部对象。
public final class Company {
final String companyName;
final Employee employee;
public Company(String companyName, Employee employee) {
this.companyName = companyName;
this.employee = new Employee(employee); // 1
}
public String getCompanyName() {
return companyName;
}
public Employee getEmployee() {
return new Employee(employee); // 2
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.