clone():ArrayList.clone()我以为是浅拷贝

ArrayList a=new ArrayList(); a.add(5); ArrayList b=(ArrayList)a.clone(); a.add(6); System.out.println(b.toString()); 

在上面的代码中,我认为clone()执行浅拷贝。 所以, ba应该指向相同的内存位置。 但是,当我执行b.toString() ,答案只有5 。 如果clone()执行浅拷贝,为什么6也不显示?

浅拷贝并不意味着它们指向相同的内存位置。 那只是一个任务: List b = a;

克隆创建一个实例, 包含相同的元素。 这意味着您有2个不同的列表,但它们的内容是相同的。 如果更改第一个列表中对象的状态,它将在第二个列表中更改。 (因为你使用的是不可变类型 – Integer – 你无法观察到这一点)

但是,您应该考虑不使用clone() 。 它适用于集合,但通常它被认为是破碎的。 使用copy-constructors – new ArrayList(originalList)

如果它像你想的那样,那么clone方法完全没用了,因为在这种情况下,以下几行是等价的:

 ArrayList b = (ArrayList)a.clone(); ArrayList b = a; 

克隆是 – 就像在现实世界中的场景一样 – 创建具有完全相同属性的两个实体的过程(在克隆操作时)。

正如Bozho所提到的 – 避免使用Java clone()概念。 即便是作者提到,它也被打破了。

这个问题和它的答案非常有价值,并提供了一个链接Josh Blochs自己对他的工作的评论;-)

浅层克隆是您正在讨论的Object.clone()提供的默认克隆策略。 对象类的clone()方法创建一个新实例,并将Cloneable对象的所有字段复制到该新实例(它是原始实例或引用)。 因此,在引用类型的情况下,只有引用位被复制到新实例,因此,两个对象的引用变量将指向同一个对象。 我们上面看到的例子是Shallow Cloning的一个例子。

深度克隆顾名思义,深度克隆意味着克隆从一个对象到另一个对象的所有东西。 为此,我们需要欺骗我们的clone()方法来提供我们自己的克隆策略。 我们可以通过在我们的对象层次结构中的每个引用类型中实现Cloneable接口和覆盖clone()方法,然后在对象的clone方法中调用super.clone()和这些clone()方法来实现。

但是如果你在源代码中查看ArrayList的clone()方法,你会看到它是在外部复制v.elementData = Arrays.copyOf(elementData, size); 在调用super.clone() ,这意味着ArrayList的clone()会深深地复制它的内容

 public Object clone() { try { ArrayList v = (ArrayList) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } } 

要阅读有关克隆及其类型(如深度克隆和浅层克隆)的更多信息,请阅读详细信息中的Java克隆和克隆类型(浅层和深层)

我们不能动态选择我们想要添加字符串的位置

 int r=k.nextInt(); Integer i6=new Integer(r); System.out.println("Enter the address"); String p6=k.nextLine(); ar3.add(i6,p6); 

它在读完整数后并没有排除它

Arraylist中的clonefunction与将一个arraylist复制到另一个arraylist不同,如果我们使用clone(),它会保留原始arraylist的副本,但是如果我们在使用clone()之后对原始arraylist进行任何更改,它将不会影响复制的arraylist ..例如:

 public static void main(String[] a) { List list = new ArrayList(); list.add("A"); List list2 = ((List) ((ArrayList) list).clone()); System.out.println(list); System.out.println(list2); list.clear(); System.out.println(list); System.out.println(list2); } 

输出: –

[一个]

[一个]

[]

[一个]

这确实是一个浅表副本,这里是来自ArrayList源代码的clone的注释

返回此ArrayList实例的浅表副本。 (元素本身不会被复制。)

为了理解这一点,让我们看看ArrayList中克隆方法的一个片段

 v.elementData = Arrays.copyOf(elementData, size); 

众所周知,当我们将一个Object分配给一个变量时,JAVA不会创建该Object的全新副本。 相反,此变量成为指向原始Object的另一个引用。

因此,elementData实际上存储对放入此ArrayList的对象的引用。 克隆只是复制这些引用,不创建对象的副本。

当然,您可以删除或添加对克隆ArrayList的新引用。

但是,在一个ArrayList中修改旧对象将影响原始ArrayList。 因为Integer是不可变的,所以很难用你的例子做插图。

要查看副作用,您可以定义自定义可变对象

 class Person { private int a; public void setA(int a) { this.a = a; } public int getA() { return a; } @Override public String toString() { return String.valueOf(a); } } 

然后,您可以使用以下代码进行测试

  Person p1 = new Person(); Person p2 = new Person(); ArrayList tt = new ArrayList(); tt.add(p1); tt.add(p2); ArrayList yy = (ArrayList) tt.clone(); Person vv = yy.get(yy.indexOf(p2)); vv.setA(12); yy.remove(p1); System.out.println("tt: " + tt); System.out.println("yy: " +yy); 

输出应该是

tt:[0,12]
yy:[12]

看副作用:)? 我们只改变yy中的元素,但它也反映在tt中。