提问人:aravindkanna 提问时间:8/31/2017 最后编辑:aravindkanna 更新时间:8/31/2017 访问量:1958
复制构造函数而不是 Java 中的克隆
Copy constructors instead of Clone in java
问:
我正在尝试在 java 中实现一个复制构造函数。我面临着类的非原始类型字段的问题。在创建新副本时,它正在共享成员。例如
public class Bad implements Cloneable {
private ArrayList<Integer> a;
private Object c;
public static void main(String[] args) {
Bad b1 = new Bad();
b1.a.add(10);
System.out.println(b1.a);
Bad b2 = b1.clone();
b2.a.add(12);
System.out.println(b1.a);
}
Bad() {
a = new ArrayList<>();
c = null;
}
Bad(Bad b) {
a = b.a;
c = b.c;
}
public Bad clone() {
return new Bad(this);
}
}
结果是:
[10]
[10, 12]
我不希望这种情况发生。以此为例。我原来的问题包括更多用户定义的字段。
或者有没有图书馆为我做这项工作?提前致谢。
答:
2赞
ΦXocę 웃 Пepeúpa ツ
8/31/2017
#1
Integer 是不可变的,但您需要创建一个全新的 ArrayList,我的意思是:
Bad(Bad b) {
a = b.a;
c = b.c;
}
请改为
Bad(Bad b) {
a = new ArrayList<>(b.a);
c = // this here must be copy constructed too
}
然后你会得到
[10]
[10]
评论
1赞
Andrew Tobilko
8/31/2017
实际参数具有 type,而字段仍然是 .你必须找到一个应对机制,以及清单Integer
Object
1赞
zdenda.online
8/31/2017
#2
正确的方法是创建列表的新实例,而不是传递对原始列表的引用。
Bad(Bad b) {
a = new ArrayList<>(b.a);
c = b.c; // this should call clone or something similar as well
}
还要注意的是,如果你在 b.a 列表中有一些非原始类型,那么你也必须复制/克隆所有子元素(现在不需要它,因为你里面有不可变的整数)。
3赞
scottb
8/31/2017
#3
复制构造函数的简单规则:
- 基元值可以按原样复制;它们只是没有单独身份的价值观
- 对不可变类型的引用(例如。String、Integer、任何枚举类常量)也可以按原样复制;尽管原始对象和复制对象将共享相同的引用,但引用的对象是不可变的,并且永远不会更改
- 对可变类型的引用(例如。Date、ArrayList、any array) 必须复制到该类型的新实例中;否则,原始对象和复制对象将共享对同一可变字段对象的引用(这不是您想要的)
创建仅包含具有基元值和不可变值的字段的对象的副本是简单模式。
复制字段包含可变对象的对象可能会使该过程变得艰巨且昂贵,具体取决于可变对象的复杂程度(假设一个 ArrayList 包含一个值也是 Map 的 Map)。但是,如果您希望拥有一个安全的副本,则必须创建可变字段的新副本。
评论
a = new ArrayList<>(b.a);
b.a