我在问及如何在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可以做多深的克隆。如果我理解克隆的错误,请纠正我。
答案 0 :(得分:4)
我认为你理解得很好:clone
是一个糟糕的机制,实际上有一个错误的完整列表(查看Effective Java)。与您的案例特别相关的是,您无法使用final
字段深度克隆对象。
而是选择复制对象的自定义机制,例如复制构造函数或专用方法。
内存序列化 - 反序列化循环也有一个技巧,但我不会真的推荐它,除非你的列表中的性能和效率不高。
答案 1 :(得分:0)
Cloneable工具的许多问题之一是,在调用super.clone()
之后,在返回克隆值之前,可能存在需要返回状态的字段和-fix-。这可以防止您在类中创建这些字段final
,并且与不可变类的原则不一致。此外,该设施可能会在您的班级中引入安全漏洞,主要是因为它依赖于创建对象的语言机制。
如果您可以避免在类中实现Cloneable,那么一个好的经验法则是,然后避免使用它。
正如Marko所提到的,复制工厂方法的复制构造者通常是优越的策略,不依赖于有缺陷的,用于创建对象的语言机制。使用我所知道的clone()
方法的唯一好处是获取不可变值数组的防御性副本,例如基元或Strings
。