Java 将ArrayList元素克隆到同一ArrayList
我有一个包含对象的Java 将ArrayList元素克隆到同一ArrayList,java,arraylist,clone,Java,Arraylist,Clone,我有一个包含对象的ArrayList。(这些对象是类别,每个对象都包含难以置信的大量信息,正是这些对象代表了大型发电机,因此不能逐个复制属性) 例如: ArrayList arr = {ob1, ob2, ob3, ob4, ob5} 因此,我尝试将对象(ob1)克隆到位置5 arr.set(4, arr.get(0)); 但不知何故,这样做,ob5不是ob1的副本,它是ob1,所以如果我改变ob5,ob1也会改变 这是ArrayList的固有特性吗? 如果我改用列表,有什么区别吗?这是因为
ArrayList
。(这些对象是类别,每个对象都包含难以置信的大量信息,正是这些对象代表了大型发电机,因此不能逐个复制属性)
例如:
ArrayList arr = {ob1, ob2, ob3, ob4, ob5}
因此,我尝试将对象(ob1)克隆到位置5
arr.set(4, arr.get(0));
但不知何故,这样做,ob5不是ob1的副本,它是ob1,所以如果我改变ob5,ob1也会改变
这是ArrayList的固有特性吗?
如果我改用列表,有什么区别吗?这是因为您正在进行卷影复制而不是深度复制 浅层复制:如果在
Obj-1
上执行浅层复制,则会复制该对象,但不会复制其包含的对象。包含的对象Obj-1
和Obj-2
受克隆的Obj-2的更改影响。默认情况下,当类实现Java.lang.Cloneable接口时,Java支持对象的浅层克隆
深度复制:如果对所示的obj-1
执行深度复制,则不仅obj-
1已被复制,而且其中包含的对象也已被复制。序列化可用于实现深度克隆。通过序列化进行深度克隆开发更快,维护更容易,但会带来性能开销
深度复制的一个示例:
class Student implements Cloneable {
//Contained object
private Subject subj;
private String name;
public Subject getSubj() {..}
public String getName() {..}
public Object clone() {
//Deep copy
Student s = new Student(name, subj.getName());
return s;
}
}
在Java的任何地方都是如此。除非您明确地这样做,否则不会复制任何内容。(事实上,有些对象是故意不可能复制的。)您需要制作一份发电机的副本。最常见的选项是引入复制构造函数或实现克隆方法。但是,这两种解决方案都需要复制所有这些属性 一旦你做到了,你就可以做到
//copy constructor
arr.add( new ElectricGenerator( arr.get( 0 ) ) );
//clone
arr.add( arr.get( 0 ).clone() );
另一种方法是序列化/反序列化对象这不符合ArrayList,这是java特性。不创建新对象,只传递引用。因此,ArrayList存储两个引用。您必须使用对象的.clone()方法
arr.set(4, arr.get(0).clone());
这将创建对象的新副本,即使此副本很浅。如果需要,您必须重写clone方法以使其成为深度副本。否,因为在Java中,您创建了对对象的引用,因此即使您不使用ArrayList并执行类似操作:
String a = new String("a");
String b = a;
b += "b";
a和b都等于“ab”
(这里的例外是int之类的基本类型(但不是Integer的实例,有不同的东西))
因此,您的问题的答案如下:
在这里:
列表仅包含指向对象的指针 如果将ob1移动到ob5,会发生什么情况?您会告诉列表将指向ob1的指针放在ob5指针所在的位置,从而丢失指向ob5的指针并复制指向ob1的指针
您需要创建另一个包含重复值的对象,然后将此对象分配到位置4对象变量不同于原始数据类型
int x = 2;
int y = x;
x和y表示不同的内存位置
MyClass x = new MyClass();
MyClass y = x;
x和y引用相同的内存位置,但该位置有两个引用。对其中一个的任何改变都会改变另一个。解决此问题的方法是实现
Cloneable
并使用.clone()
方法。浅层复制
创建同一类的新实例,并将所有字段复制到新实例并返回它。对象类提供克隆方法并支持浅层复制。ArrayList保存引用是。但您可以克隆它(注意!但它将是浅拷贝-对于内部对象,它也不会克隆)
然后像这样使用
JustToCheck ob1 = new JustToCheck();
JustToCheck ob2 = ob1;
List<JustToCheck> arr = new ArrayList<JustToCheck>();
arr.add(ob1);
arr.add(ob2);
System.out.println(arr.get(0).toString() + ": " + arr.get(1).toString());
try {
arr.set(1, (JustToCheck) ob1.clone());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
System.out.println(arr.get(0).toString() + ": " + arr.get(1).toString());
PS-我已经在答案中检查了这个问题 有些东西是不可变的 爪哇6
JustToCheck ob1 = new JustToCheck();
JustToCheck ob2 = ob1;
List<JustToCheck> arr = new ArrayList<JustToCheck>();
arr.add(ob1);
arr.add(ob2);
System.out.println(arr.get(0).toString() + ": " + arr.get(1).toString());
try {
arr.set(1, (JustToCheck) ob1.clone());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
System.out.println(arr.get(0).toString() + ": " + arr.get(1).toString());
example$JustToCheck@1c39a2d: example$JustToCheck@1c39a2d
example$JustToCheck@1c39a2d: example$JustToCheck@bf2d5e
String a = new String("a");
String b = a;
b += "b";
System.out.println("a = " + a); // a = a
System.out.println("b = " + b); // b = ab