[英]My class needs to be immutable but I need a copy constructor, and since my fields aren't initialized, the constructor gives me an error
因此,我目前正在從事一成不變的課程。
package sysutilities;
public final class Address {
// Initializing fields/////////////////////////////////////////////////////
private final String street, city, state, zip;
//Constructor with 4 parameters - street, city, state and zip code/////////
public Address(String street, String city, String state, String zip) {
this.street = street.trim();
this.city = city.trim();
this.state = state.trim();
this.zip = zip.trim();
if (this.street == null || this.city == null || this.state == null ||
this.zip == null || !this.zip.matches("\\d+")) {
throw new IllegalArgumentException("Invalid Address Argument");
}
}
//Default Constructor//////////////////////////////////////////////////////
public Address() {
this.street = "8223 Paint Branch Dr.";
this.city = "College Park";
this.state = "MD";
this.zip = "20742";
}
//Copy Constructor/////////////////////////////////////////////////////////
public Address(Address inp) {
Address copyc = new Address();
}
出現我的問題的原因是,如果緊鄰緊鄰的最終私有字段,則復制構造函數顯然無法執行其工作。 所以我的代碼給我一個錯誤。 但是,如果我嘗試在開始時將字段初始化為null,則程序的其余部分將給我一個錯誤。
沒有私有的final字段,有什么方法可以保留類的不變性?
您的構造函數不應創建另一個Address對象。 它應該初始化由構造函數構造的該地址的字段:
public Address(Address inp) {
this.street = inp.street;
this.city = inp.city;
...
}
要么
public Address(Address inp) {
this(inp.street, inp.city, ...);
}
但是,正如安迪·特納(Andy Turner)在其評論中正確提及的那樣,如果一個類是不可變的,則沒有理由創建其任何實例的副本,因為它們可以在對象和線程之間重用和共享而沒有任何風險。
如果我使用復制構造函數運行您的代碼,您不會說會遇到什么錯誤
public Address(Address a) {
Address c = new Address();
}
那么我會收到“變量街道可能尚未初始化”的信息,這是有道理的,因為通過調用Address構造函數創建的實例永遠不會獲得為其最終字段設置的任何值。 在構造函數中創建局部變量不會初始化正在構造的實例。 構造函數不返回任何內容,您所能做的就是在要初始化的實例上設置字段。 還要注意,傳入的地址未使用。
正如其他人所說,沒有充分的理由制作不可變對象的副本。 但這是您的家庭作業。
您的驗證有誤; 例如,如果您為街道傳入null,則將獲得NullPointerException。 永遠不會達到驗證檢查。 (這就是為什么人們為他們的代碼編寫測試的原因。)另外,其他構造函數也無法利用第一個構造函數中的驗證。
接受參數的構造函數在嘗試對它們進行任何操作之前,需要檢查傳入的參數:
public Address(String street, String city, String state, String zip) {
if (street == null || city == null || state == null ||
zip == null || !zip.matches("\\d+")) {
throw new IllegalArgumentException("Invalid Address Argument");
}
this.street = street.trim();
this.city = city.trim();
this.state = state.trim();
this.zip = zip.trim();
}
當然,由於您忽略了導致該問題的字段,因此異常消息是含糊的。 最好有單獨的測試,並使用更具體的消息引發異常。
可以將no-arg構造函數鏈接到另一個:
public Address() {
this("8223 Paint Branch Dr.", "College Park", "MD", "20742");
}
這樣,您就沒有兩個用於初始化對象的單獨路徑。 如果在其他構造函數中確實具有有效的驗證代碼,則當前的no-arg構造函數將不會使用它。 但是,如果以這種方式鏈接構造函數,則兩個路徑都將得到驗證。
將您的復制構造函數更改為
public Address(Address inp) {
this(inp.street, inp.city, inp.state, inp.zip);
}
將允許它共享存在於主構造函數中的驗證代碼。 在此示例中,這無關緊要,因為您從一個大概有效的對象獲取輸入,但是總的來說,使構造函數協同工作有助於避免錯誤,這是一個錯誤發生的示例,因為存在不同的初始化方式一個對象 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.