このフィールドごとのコピーは、object.clone()によって行われたものは何ですか?
質問
効果的なJavaでは、著者は次のように述べています。
クラスがクローン可能なものを実装する場合、オブジェクトのクローンメソッドはオブジェクトのフィールドバイフィールドコピーを返します。それ以外の場合は、CloneNotsupportedExceptionを投げます。
私が知りたいのは、フィールドバイフィールドのコピーで彼が何を意味するかです。それは、クラスにメモリにxバイトがある場合、そのメモリの一部をコピーするだけだということですか?はいの場合、元のクラスのすべての値タイプが新しいオブジェクトにコピーされると仮定できますか?
class Point implements Cloneable{
private int x;
private int y;
@Override
public Point clone() {
return (Point)super.clone();
}
}
もし何か Object.clone()
は、フィールドコピーによるフィールドです Point
クラス、私はフィールドを明示的にコピーする必要はないと思います x
と y
, 、上記のコードがクローンを作成するのに十分すぎるということです Point
クラス。つまり、次のコードは冗長です。
@Override
public Point clone() {
Point newObj = (Point)super.clone();
newObj.x = this.x; //redundant
newObj.y = this.y; //redundant
}
私は正しいですか?
クローンされたオブジェクトの参照は、元のオブジェクトの参照が指し示している場所を自動的に指していることを知っていますが、値タイプで特に何が起こるかわかりません。誰かがはっきりと述べることができれば Object.clone()
のアルゴリズム仕様は(簡単な言語で)素晴らしいものです。
解決
はい、フィールドバイフィールドコピーは、新しい(クローン化された)オブジェクトを作成すると、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のクローニングを使用しないことを好みます。代わりに、私は通常、独自の「複製」方法を作成します。
他のヒント
それは浅いコピーを意味します - フィールドがコピーされますが、参照がある場合、これらのポイントがコピーされていません - 同じオブジェクトに2つの参照があります。物体。ただし、プリミティブタイプを持つフィールドの場合、フィールドはデータ自体であるため、関係なくコピーされます。
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;
デフォルトのクローンは、値の浅いコピーを実行します。プリミティブ値には、これで十分であり、追加の作業は必要ありません。
オブジェクトの場合、浅いコピーは参照のみをコピーすることを意味します。したがって、これらの場合、通常、深いコピーが必要です。これの例外は、参照が不変のオブジェクトを指している場合です。不変のオブジェクトは、明らかな状態を変更することはできないため、参照を安全にコピーできます。たとえば、これは文字列、整数、フロート、列挙に適用されます(誤って変換されない場合)。