【问题标题】:Undesrstanding clone method for arrays了解数组的克隆方法
【发布时间】:2015-09-12 03:26:49
【问题描述】:

我了解到,对于数组,clone 方法表现良好,我们可以使用它。但我认为数组持有的元素类型应该已经实现了Cloneable接口。让我举个例子:

public class test {

    public static void main(String[] args){
        Test[] arr_t = new Test[1];
        arr_t[0] = new Test(10);
        Test[] an_arr = arr_t.clone(); 
        an_arr[0]= new Test(5);
        System.out.println(an_arr[0].test); //5
        System.out.println(arr_t[0].test);  //10
    }

    public static class Test{
        public int test;
        public Test(int test) {
            this.test = test;
        }
    }
}

DEMO

我认为 5 应该打印两次。这样做的原因是通过克隆数组,我们创建了新数组,其中包含对第一个数组持有的对象的引用(因为元素的类型没有实现Cloneable)。你不能把事情弄清楚吗?

不清楚数组元素的类型是否需要实现Cloneable

【问题讨论】:

  • @zubergu 为什么?为什么要克隆数组?
  • @zubergu 好吧,我会说与Cloneableclone 相关的一切都不合逻辑和预期......这是我的诚实意见,不再......

标签: java arrays clone cloneable


【解决方案1】:

这是一个简单的概念,但似乎很难解释。克隆数组时,内存中有两个分区数组,但它们的索引值相同。


在您的第二个数组an_arr 中执行an_array[0] = new Test(5) 您将在插槽0 中放置另一个引用。

但是克隆的索引 0 与克隆的数组在不同的位置。

如果你这样做,你的例子是有效的

Test[] arr_t = new Test[1];
arr_t[0] = new Test(10);
Test[] an_arr = arr_t.clone(); 
an_arr[0].test = 5; // look here, I changed the object
System.out.println(an_arr[0].test); //5
System.out.println(arr_t[0].test);  //5

现在两者都将打印相同的值,因为它们对同一个对象持有相同的引用,但该引用的存储位置不同。

【讨论】:

  • 所以,当我们克隆一个数组时,我们不用担心数组元素的类型是否实现了Cloneable
  • 是的,因为它不会复制元素只是引用(这是一个简单的值 0x595959ff(示例))
  • 啊,你说得对。我只是对此有点困惑......谢谢。
【解决方案2】:

.clone() 制作所谓的“浅拷贝”。这意味着它在运行该方法时尽可能少地复制;而不是复制数组的 contents,它只是创建对原始数组内容的引用。

如果您通过调用更改引用:

new Test(5)

然后您已经覆盖了该引用,并获取了新数据。

另一种方法是数组的深层副本。对较大的对象执行这些操作可能会很昂贵,因此它们不是默认设置。

【讨论】:

    【解决方案3】:

    无论数组的类型如何,数组的clone() 都会做同样的事情:它创建一个相同类型和大小的新数组,然后将数组的每个元素(=)分配给新数组的每个元素。就是这样。

    因此,如果您有一个由arr 指向的三元素数组,并且arr.clone() 返回newArr,那么在创建新数组之后,它只需执行以下操作:

    newArr[0] = arr[0];
    newArr[1] = arr[1];
    newArr[2] = arr[2];
    

    就是这样。数组的类型不相关。元素中没有“克隆”或任何内容。它不知道(或关心)元素是否有某种克隆方法(事实上,Java 中并没有通用的克隆 API,所以这是不可能的)。

    (顺便说一句,即使它以某种方式将克隆的对象放入新数组中,您的示例中的结果仍然是相同的,因为您正在为数组分配一个新值,所以没关系以前有过。)

    所以你的问题基本上是为什么:

    Test[] arr_t = new Test[1];
    arr_t[0] = new Test(10);
    Test[] an_arr = new Test[1];
    an_arr[0] = arr_t[0]; 
    an_arr[0] = new Test(5);
    System.out.println(an_arr[0].test); //5
    System.out.println(arr_t[0].test);  //10
    

    你可以从那里弄清楚。

    【讨论】:

      【解决方案4】:

      这里的“问题”是数组持有对象的引用,而不是对象。此外,这与克隆无关。

      当你执行时:

      an_arr[0] = new Test(5);
      

      您正在将新对象的引用分配给第一个元素。

      此外,每个数组都有自己对 Test 对象的引用。克隆数组时,只会复制引用(而不是它们所引用的对象)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-18
        • 1970-01-01
        • 1970-01-01
        • 2013-06-12
        • 1970-01-01
        • 2011-04-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多