簡體   English   中英

我的類必須是不可變的,但我需要一個復制構造函數,並且由於未初始化字段,因此構造函數給我一個錯誤

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM