0

首先,我不得不说这不是deep copying vs shallow copying (clone)Java 中的副本。但它与此有关。我已经阅读deep vs shallow copying了 SO 中的其他帖子,在处理这个问题时,我发现我的理解存在一些问题。问题是:clone() and system.arraycopy()在下面的示例中给出不同的数组。但他们不应该这样做?

我在下面的另一个示例对象中使用数组作为字段。我再次看到它们是数组字段的不同引用。代码被注释以便于理解。

import java.util.Arrays;
import java.util.*;


class Example {
        public int foo;
        public int[] bar;

        public Example (int foo, int[] bar) {
         this.foo = foo; 
        this.bar = bar; 
        }
        public void setfoo(int foo){
            this.foo=foo;
        }
        public int[] getbar(){
            return bar;
        }
}
public class ClonevsDeepCopy {
    public static void main(String[] args){
        //Example 1
        StringBuffer[] arr = {new StringBuffer("abc"),new StringBuffer("def"),
                                     new StringBuffer("ghi")};
        StringBuffer[] arr2 = arr.clone();
        StringBuffer[] arr3 = new StringBuffer[3];
        System.arraycopy(arr, 0, arr3, 0, 2);
        //check for identity
        System.out.println(arr==arr2);
        System.out.println(arr==arr3);
        //End of example 1

        //Example 2
        /*this is equivalent of shallow copying which is clone()
         * The normal interpretation is that a "shallow" copy of eg1 
         * would be a new Example object whose foo equals 1 
         * and whose bar field refers to the same array as in the original; e.g.
         */
        Example eg1 = new Example(1, new int[]{1, 2});
        Example eg2 = new Example(eg1.foo,eg1.bar);
        System.out.println(eg1.bar==eg2.bar);
        eg1.setfoo(4);
        eg1.bar[0]=99;

        /*This is equivalent of deep coying
        The normal interpretation of a "deep" copy of eg1 would 
        be a new Example object whose foo equals 
        1 and whose bar field refers to a copy of the original array; e.g.
        */
        Example eg3 = new Example(eg1.foo,Arrays.copyOfRange(eg1.bar, 0, 2));
        System.out.println(eg3.bar==eg1.bar);
        //cloning on array
        Example eg4 = new Example(eg1.foo,eg1.bar.clone());
        System.out.println(eg4.bar==eg1.bar);
        //End of example 2




    }

}
4

3 回答 3

2

这里没有什么奇怪的。

如果arr1是结果或者arr.clone()那么arr1!=arr但是arr1[0]==arr[0]如果它被定义。Ifarr1=arr是作业 then arr1==arr

细节:

我们有 5 个结果:

falseSystem.out.println(arr==arr2);

这里没什么奇怪的,我们比较的是数组引用本身,而不是内容。

falseSystem.out.println(arr==arr3);

没什么奇怪的,不同的数组。

trueSystem.out.println(eg1.bar==eg2.bar);

没什么奇怪的,相同的参考。

最后两个false

同样,我们正在执行一些浅拷贝。元素仍然是相等的引用,但数组是不同的引用。

于 2013-09-12T19:41:28.910 回答
1

我不知道是什么让你感到困惑。System.arraycopy()将元素从一个数组复制到另一个数组。它没有参考。

Array#clone()javadoc 状态

一般意图是,对于任何对象 x,表达式:

x.clone() != x

因此,您将获得不同的参考。

更多详情

StringBuffer[] arr = {new StringBuffer("abc"),new StringBuffer("def"),
                                 new StringBuffer("ghi")};
StringBuffer[] arr2 = arr.clone();
StringBuffer[] arr3 = new StringBuffer[3];

您有 3 个不同的参考。然后,查看代码注释

System.arraycopy(arr, 0, arr3, 0, 2); // copy values from arr into arr, the references haven't changed
//check for identity
System.out.println(arr==arr2); // different references
System.out.println(arr==arr3); // different references

Arrays.copyOf()返回一个数组(新引用),其中包含源数组中的值。

Example eg3 = new Example(eg1.foo,Arrays.copyOfRange(eg1.bar, 0, 2));

所以

System.out.println(eg3.bar==eg1.bar);

false

和更多

   Example eg4 = new Example(eg1.foo,eg1.bar.clone());
   System.out.println(eg4.bar==eg1.bar);

clone()返回一个新的引用,因此您再次比较不同的引用并获取false.

如果您要比较数组的内容,请使用

Arrays.equals(arr, arr2); // for example

请注意,由于原始类型,这并不重要,但如果您的数组包含引用类型,您可能会关心浅拷贝或深拷贝。

于 2013-09-12T19:41:15.827 回答
0

object如果您将类型及其所有派生词视为持有“对象标识符”,则会避免很多混淆。类型变量StringBuffer不包含StringBuffer--it 的实例,它包含对象标识符,如果非空白(即非空),将标识StringBuffer. 同样,类型变量StringBuffer[]不包含数组——它包含一个对象标识符,如果非空白,它将标识一个实例StringBuffer[],反过来,将不包含 的实例StringBuffer,而是标识它们。

当代码说someVariable.someMember=5;时,代码没有写入someVariable. 相反,它检查someVariable、注意它识别的对象,然后修改该对象的适当字段。看起来好像语句的右手部分与 有关系someVariable,但事实并非如此。一旦系统确定由 标识的对象someVariable,该变量将不在图片中。

于 2013-09-20T21:14:48.133 回答