在 java 中复制构造函数而不是克隆
Copy constructors instead of Clone in java
我正在尝试在 java 中实现复制构造函数。我面临 class 的非原始类型字段的问题。在创建新副本时,它正在共享成员。例如
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]
我不希望这种情况发生。以此为例。我的原始问题包含更多用户定义的字段。
或者有没有图书馆可以帮我完成这项工作?提前致谢。
整数是不可变的,但您需要创建一个全新的 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]
正确的方法是创建列表的新实例,而不是传递对原始列表的引用。
Bad(Bad b) {
a = new ArrayList<>(b.a);
c = b.c; // this should call clone or something similar as well
}
另请注意,如果 b.a 列表中有一些非原始类型,那么您还必须 copy/clone 所有子元素(现在不需要因为你有整数,它是不可变的)。
复制构造函数的简单规则:
- 原始值可以按原样复制;它们只是没有单独标识的值
- 对不可变类型的引用(例如字符串、整数、任何枚举 class 常量)也可以按原样复制;尽管原始对象和复制的对象将共享相同的引用,但引用的对象是不可变的,永远不会改变
- 对可变类型的引用(例如日期、ArrayList、任何数组)必须复制到该类型的新实例;否则原始对象和复制对象将共享对同一个可变字段对象的引用(这不是你想要的)
复制仅包含具有原始值和不可变值的字段的对象是简单模式。
根据可变对象的复杂程度,复制其字段包含可变对象的对象可能会使过程变得艰巨和昂贵(想象一个包含 Map 的 ArrayList,其值也是 Map)。但是,如果您希望拥有一份安全的副本,则必须制作一份新的可变字段副本。
我正在尝试在 java 中实现复制构造函数。我面临 class 的非原始类型字段的问题。在创建新副本时,它正在共享成员。例如
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]
我不希望这种情况发生。以此为例。我的原始问题包含更多用户定义的字段。
或者有没有图书馆可以帮我完成这项工作?提前致谢。
整数是不可变的,但您需要创建一个全新的 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]
正确的方法是创建列表的新实例,而不是传递对原始列表的引用。
Bad(Bad b) {
a = new ArrayList<>(b.a);
c = b.c; // this should call clone or something similar as well
}
另请注意,如果 b.a 列表中有一些非原始类型,那么您还必须 copy/clone 所有子元素(现在不需要因为你有整数,它是不可变的)。
复制构造函数的简单规则:
- 原始值可以按原样复制;它们只是没有单独标识的值
- 对不可变类型的引用(例如字符串、整数、任何枚举 class 常量)也可以按原样复制;尽管原始对象和复制的对象将共享相同的引用,但引用的对象是不可变的,永远不会改变
- 对可变类型的引用(例如日期、ArrayList、任何数组)必须复制到该类型的新实例;否则原始对象和复制对象将共享对同一个可变字段对象的引用(这不是你想要的)
复制仅包含具有原始值和不可变值的字段的对象是简单模式。
根据可变对象的复杂程度,复制其字段包含可变对象的对象可能会使过程变得艰巨和昂贵(想象一个包含 Map 的 ArrayList,其值也是 Map)。但是,如果您希望拥有一份安全的副本,则必须制作一份新的可变字段副本。