在java中复制构造函数而不是克隆

在java中复制构造函数而不是克隆,java,reference,clone,copy-constructor,Java,Reference,Clone,Copy Constructor,我试图用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)

我试图用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);
    }
}
我不想发生这种事。以此为例,。我的原始问题包括更多用户定义的字段。

或者有没有为我做这项工作的图书馆?提前感谢。

整数是不可变的,但您需要创建一个全新的数组列表,我的意思是:

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
}
坏(坏b){
a=新阵列列表(b.a);
c=//这里也必须是复制构造的
}
然后你会得到

[10]

[10]


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
}
坏(坏b){
a=新阵列列表(b.a);
c=//这里也必须是复制构造的
}
然后你会得到

[10]

[10]


正确的方法是创建列表的新实例,而不是传递对原始列表的引用

Bad(Bad b) {
  a = new ArrayList<>(b.a);
  c = b.c; // this should call clone or something similar as well
}
坏(坏b){
a=新阵列列表(b.a);
c=b.c;//这应该调用clone或类似的东西
}

还请注意,如果在b.a的列表中有一些非原语类型,那么您还必须复制/克隆所有子元素(现在不需要它,因为其中有整数,它是不可变的)。

正确的方法是创建列表的新实例,而不是传递对原始列表的引用

Bad(Bad b) {
  a = new ArrayList<>(b.a);
  c = b.c; // this should call clone or something similar as well
}
坏(坏b){
a=新阵列列表(b.a);
c=b.c;//这应该调用clone或类似的东西
}

还请注意,如果在b.a列表中有一些非原语类型,则还必须复制/克隆所有子元素(现在不需要,因为其中包含整数,它是不可变的)。

复制构造函数的简单规则:

  • 原语值可以原样复制;它们只是没有单独标识的值
  • 对不可变类型的引用(例如字符串、整数、任何枚举类常量)也可以按原样复制;虽然原始对象和复制对象将共享相同的引用,但引用的对象是不可变的,并且永远不会更改
  • 对可变类型的引用(例如日期、ArrayList、任意数组)必须复制到该类型的新实例中;否则,原始对象和复制对象将共享对同一可变字段对象的引用(这不是您想要的)
创建仅包含具有基本值和不可变值的字段的对象副本是一种简单的模式


复制一个字段中包含可变对象的对象可能会使过程变得繁重和昂贵,具体取决于可变对象的复杂程度(想象一个ArrayList,其中包含一个值也是映射的映射)。但是,如果您希望有一个安全副本,则创建可变字段的新副本是必不可少的。

复制构造函数的简单规则:

  • 原语值可以原样复制;它们只是没有单独标识的值
  • 对不可变类型的引用(例如字符串、整数、任何枚举类常量)也可以按原样复制;虽然原始对象和复制对象将共享相同的引用,但引用的对象是不可变的,并且永远不会更改
  • 对可变类型的引用(例如日期、ArrayList、任意数组)必须复制到该类型的新实例中;否则,原始对象和复制对象将共享对同一可变字段对象的引用(这不是您想要的)
创建仅包含具有基本值和不可变值的字段的对象副本是一种简单的模式


复制一个字段中包含可变对象的对象可能会使过程变得繁重和昂贵,具体取决于可变对象的复杂程度(想象一个ArrayList,其中包含一个值也是映射的映射)。但是,如果您希望获得一个安全副本,则创建可变字段的新副本是必不可少的。

尝试
a=new ArrayList(b.a)
这将创建一个新的arrayList,其中包含
b.a
try
a=newarraylist(b.a)中的内容
这将创建一个新的arrayList,其中包含
b.a
中的内容。实际参数的类型为
Integer
,而字段仍然是
对象。您必须为该列表以及实际参数找到应对机制。实际参数的类型为
整数
,而字段仍然是
对象
。你必须找到一个应对机制,以及清单