[英]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.