java - 我的类需要是不可变的,但我需要一个复制构造函数,并且由于我的字段未初始化,构造函数给我一个错误

标签 java private immutability copy-constructor final

所以我目前正在研究一个应该是不可变的类。

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();

}

我的问题出现了,因为如果紧邻有 final 私有(private)字段,复制构造函数显然无法完成其工作。所以我的代码在那里给我一个错误。但是,如果我尝试在开始时将字段初始化为 null,我的程序的其余部分会给我一个错误。

有什么方法可以在没有私有(private) final 字段的情况下保持类的不变性?

最佳答案

如果我用像这样的复制构造函数运行你的代码,你不会说你得到了什么错误

public Address(Address a) {
    Address c = new Address();
}

然后我得到“变量街道可能尚未初始化”,这是有道理的,因为通过调用 Address 构造函数创建的实例永远不会为其最终字段设置任何值。在构造函数中创建局部变量不会对您正在构造的实例进行任何初始化。构造函数不返回任何内容,您所能做的就是在正在初始化的实例上设置字段。另请注意,传入的地址未被使用。

正如其他人所说,没有充分的理由复制不可变对象(immutable对象)。但那是你的功课。

您的验证有误;例如,如果您为街道传递一个空值,您将得到一个 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();
}

当然,异常消息是含糊不清的,因为您忽略了导致问题的字段。最好进行单独的测试并使用更具体的消息抛出异常。

无参数构造函数可以链接到另一个构造函数:

public Address() {
    this("8223 Paint Branch Dr.", "College Park", "MD", "20742");
}

这样你就没有两个单独的路径来初始化你的对象。如果您在其他构造函数中确实有有效的验证代码,则您当前的无参数构造函数将不会使用它。但是,如果您以这种方式链接构造函数,则两条路径都会得到验证。

将复制构造函数更改为

public Address(Address inp) {
    this(inp.street, inp.city, inp.state, inp.zip);
}

将允许它共享位于主构造函数中的验证代码。在这个例子中这并不重要,因为您从一个可能有效的对象中获取输入,但通常让构造函数一起工作有助于避免错误,这里是 an example of where an error occurred because there were different ways to initialize an object .

关于java - 我的类需要是不可变的,但我需要一个复制构造函数,并且由于我的字段未初始化,构造函数给我一个错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33488417/

相关文章:

security - 变量隐私实际上与安全性有什么关系,还是只是为了编程方便?

swift - 如何覆盖私有(private) init

java - 从方法返回可变对象的不可变副本

typescript - 如何使用 Typescript 正确地将 Immutable Map 转换为严格类型

java - WindowBuilder 与 JavaFX Scenebuilder 按钮操作?

java - 将 ASCII 值写入 RS485 等串行通信设备的寄存器

java - 收到错误消息说类未与命名查询映射

java - RESTEasy注解扫描找不到资源(Tomcat下)

C++11:私有(private)成员安全

scala - 条件变量设置