12

効果的なJavaで、著者は次のように述べています。

クラスがCloneableを実装している場合、Objectのcloneメソッドはオブジェクトのフィールドごとのコピーを返します。それ以外の場合は、CloneNotSupportedExceptionをスローします。

私が知りたいのは、フィールドごとのコピーで彼が何を意味するのかということです。クラスのメモリにXバイトがある場合、そのメモリの一部をコピーするだけだということですか?はいの場合、元のクラスのすべての値型が新しいオブジェクトにコピーされると想定できますか?

class Point implements Cloneable{
    private int x;
    private int y;

    @Override
    public Point clone() {
        return (Point)super.clone();
    }
}

Object.clone()クラスのフィールドごとのコピーが何であるかというと、Pointフィールドを明示的にコピーする必要はないと思います。上記のコードは、クラスのクローンを作成するのに十分すぎるほどです。つまり、次のコードは冗長です。xyPoint

@Override
public Point clone() {
    Point newObj = (Point)super.clone();
    newObj.x = this.x; //redundant
    newObj.y = this.y; //redundant
}

私は正しいですか?

複製されたオブジェクトの参照は、元のオブジェクトの参照が指している場所を自動的に指すことを知っていますが、値型で具体的に何が起こるかはわかりません。誰かがObject.clone()のアルゴリズム仕様が(簡単な言語で)何であるかを明確に述べることができれば、それは素晴らしいことです。

4

4 に答える 4

5

はい、フィールドごとのコピーは、新しい (複製された) オブジェクトを作成するときに、JVM がすべてのフィールドの値を元のオブジェクトから複製されたオブジェクトにコピーすることを意味します。残念ながら、これは浅いコピーがあることを意味します。ディープ コピーが必要な場合は、クローン メソッドをオーバーライドできます。

class Line implements Cloneable {

    private Point start;
    private Point end;

    public Line() {
        //Careful: This will not happen for the cloned object
        SomeGlobalRegistry.register(this);
    }

    @Override
    public Line clone() {
        //calling super.clone is going to create a shallow copy.
        //If we want a deep copy, we must clone or instantiate
        //the fields ourselves
        Line line = (Line)super.clone();
        //assuming Point is cloneable. Otherwise we will
        //have to instantiate and populate it's fields manually
        line.start = this.start.clone();
        line.end = this.end.clone;
        return line;
    }
}

また、複製に関するもう 1 つの重要な点は、複製されたオブジェクトのコンストラクターが呼び出されることはありません (フィールドのみがコピーされる) ことです。そのため、コンストラクターが外部オブジェクトを初期化するか、このオブジェクトを何らかのレジストリーに登録すると、複製されたオブジェクトに対しては発生しません。

個人的には、Java のクローンを使用しないことを好みます。代わりに、通常は独自の「複製」メソッドを作成します。

于 2010-05-23T04:22:27.467 に答える
4

これは浅いコピーを意味します-フィールドはコピーされますが、参照がある場合、これらが指すものはコピーされません-同じオブジェクトへの2つの参照があります。1つは古いオブジェクトに、もう1つは新しいクローンになります。物体。ただし、プリミティブ型のフィールドの場合、フィールドはデータ自体であるため、関係なくコピーされます。

于 2010-05-23T01:01:16.163 に答える
4
newObj.x = this.x; //redundant
newObj.y = this.y; //redundant

そうです - オブジェクトの clone() メソッドによって既にコピーされているため、これらは冗長です。

データのコピーと考えるのが正しいです。プリミティブ型がコピーされ、同じオブジェクトを指すように参照もコピーされます。例えば、

class A implements Cloneable {
  Object someObject;
}

A a = new A();
a.someObject = new Object();

A cloneA = (A)a.clone();
assert a.someObject==cloneA.someObject;
于 2010-05-23T01:38:59.460 に答える
1

デフォルトのクローンは、値の浅いコピーを実行します。プリミティブ値の場合、これで十分であり、追加の作業は必要ありません。

オブジェクトの場合、浅いコピーは参照のみをコピーすることを意味します。したがって、このような場合、通常はディープ コピーが必要になります。これの例外は、参照が不変オブジェクトを指している場合です。不変オブジェクトは見かけの状態を変更できないため、参照を安全にコピーできます。たとえば、これは文字列、整数、浮動小数点数、列挙型に適用されます (誤って変更可能にされていない場合)。

于 2010-05-23T06:15:54.607 に答える