如何创建具有可变对象的不可变类作为引用

时间:2015-07-22 14:53:55

标签: java

我在问及如何在java中制作不可变对象时提出非常基础的问题'。

所以我有一个来自第三方的Address类,它不继承任何Cloneable接口及其可变类。看起来像这样

public class Address {

    private String city;
    private String address;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

现在我有另一个名为Person的不可变类,它实现了Cloneable接口,并且还覆盖了clone方法.Class看起来像这样

public class Person implements Cloneable {

    private String name;
    private Address address;

    public Person() {

    }

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
        //this.address = (Address) address.clone();
    }

    public String getName() {
        return name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person person = (Person) super.clone();
        return super.clone();
    }

    public Address getAddress() {
        return address;
    }

    @Override
    public String toString() {
        return "name:" + name + ", address" + address.getAddress() + ", city="
                + address.getCity();
    }

}

现在我的问题是,我肯定可以克隆Person类对象但是如何克隆地址类实例。我还阅读了一些关于浅层克隆和深度克隆的文章。但我无法理解使用三十方API可以做多深的克隆。如果我理解克隆的错误,请纠正我。

2 个答案:

答案 0 :(得分:4)

我认为你理解得很好:clone是一个糟糕的机制,实际上有一个错误的完整列表(查看Effective Java)。与您的案例特别相关的是,您无法使用final字段深度克隆对象。

而是选择复制对象的自定义机制,例如复制构造函数或专用方法。

内存序列化 - 反序列化循环也有一个技巧,但我不会真的推荐它,除非你的列表中的性能和效率不高。

答案 1 :(得分:0)

Cloneable工具的许多问题之一是,在调用super.clone()之后,在返回克隆值之前,可能存在需要返回状态的字段和-fix-。这可以防止您在类中创建这些字段final,并且与不可变类的原则不一致。此外,该设施可能会在您的班级中引入安全漏洞,主要是因为它依赖于创建对象的语言机制。

如果您可以避免在类中实现Cloneable,那么一个好的经验法则是,然后避免使用它。

正如Marko所提到的,复制工厂方法的复制构造者通常是优越的策略,不依赖于有缺陷的,用于创建对象的语言机制。使用我所知道的clone()方法的唯一好处是获取不可变值数组的防御性副本,例如基元或Strings