0

deep copying vs shallow copying (clone)まず、これはJavaの複製ではないと言わざるを得ません。しかし、それはそれに関連しています。SOの他の投稿を読みましたが、これdeep vs shallow copyingに取り組んでいるときに、理解に問題があることがわかりました。質問は次のとおりです。以下の例で異なる配列を提供します。しかし、彼らはそうすべきではないのですか?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

ここには何も奇妙なことはありません。

Ifarr1が結果である場合、またはarr.clone()then arr1!=arrbutarr1[0]==arr[0]が定義されている場合。Ifarr1=arrが割り当て thenarr1==arrです。

詳細:

5 つの結果があります。

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

ここで奇妙なことはありません。内容ではなく、配列参照自体を比較しています。

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

奇妙なことは何もありません。異なる配列です。

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

奇妙なことは何もありません。同じ参照です。

最後の 2 つ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()は新しい参照を返すため、異なる参照と get を再び比較していますfalse

配列の内容を比較する場合は、次を使用します

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

ここでは、プリミティブ型のため問題にならないことに注意してください。ただし、配列が参照型を保持している場合は、浅いコピーまたは深いコピーを気にする可能性があります。

于 2013-09-12T19:41:15.827 に答える
0

object型とそのすべての派生物が「オブジェクト識別子」を保持していると見なすと、多くの混乱を避けることができます。タイプの変数はStringBufferのインスタンスを保持しませんStringBuffer-- 非空白 (つまり、null でない) の場合、 のインスタンスを識別するオブジェクト識別子を保持しますStringBuffer。同様に、 type の変数はStringBuffer[]配列を保持しません。これはオブジェクト識別子を保持します。オブジェクト識別子は、空白でない場合、そのインスタンスを識別し、そのインスタンスをStringBuffer[]保持しませんがStringBuffer、代わりにそれらを識別します。

コードが と言うときsomeVariable.someMember=5;、コードは に書き込んでいませんsomeVariable。代わりに、 を調べsomeVariableて識別したオブジェクトを認識し、そのオブジェクトの適切なフィールドを変更します。ステートメントの右側部分が と関係があるように見えるかもしれsomeVariableませんが、そうではありません。によって識別されるオブジェクトをシステムが特定するsomeVariableと、その変数は対象外になります。

于 2013-09-20T21:14:48.133 に答える