コピーコンストラクタとは?
誰かが防御的コピーの原則と一緒に理解するのに役立つ小さな例を共有できますか?
良い例を次に示します。
class Point {
final int x;
final int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
Point(Point p) {
this(p.x, p.y);
}
}
Point(Point p)
コンストラクターが を受け取り、Point
そのコピーを作成する方法に注意してください。これはcopy constructor
.
これがdefensive
コピーであるのは、オリジナルPoint
をコピーすることによって変更から保護されているためです。
だから今:
// A simple point.
Point p1 = new Point(3,42);
// A new point at the same place as p1 but a completely different object.
Point p2 = new Point(p1);
これは必ずしもオブジェクトを作成する正しい方法ではないことに注意してください。ただし、同じオブジェクトへの 2 つの参照が誤って作成されることがないようにするには、オブジェクトを作成するのに適した方法です。明らかに、これはあなたが達成したいことである場合にのみ良いことです。
C++ でよく見かけるコピー コンストラクターは、部分的に隠され、自動的に呼び出される操作に必要です。
java java.awt.Point
頭に浮かぶRectangle
; また、非常に古い可変オブジェクト。
String
、またはのような不変オブジェクトを使用するBigDecimal
ことで、オブジェクト参照を割り当てるだけで済みます。実際、C++ 後の Java の初期段階のため、 Stringにはまだばかげたコピー コンストラクターがあります。
public class Recipe {
List<Ingredient> ingredients;
public Recipe() {
ingredients = new ArrayList<Ingredient>();
}
/** Copy constructor */
public Recipe(Recipe other) {
// Not sharing: ingredients = other.ingredients;
ingredients = new ArrayList<>(other.ingredients);
}
public List<Ingredient> getIngredients() {
// Defensive copy, so others cannot change this instance.
return new ArrayList<Ingredient>(ingredients);
// Often could do:
// return Collections.immutableList(ingredients);
}
}
要求に応じて
コピー コンストラクターを使用したクラスのリーク:
public class Wrong {
private final List<String> list;
public Wrong(List<String> list) {
this.list = list; // Error: now shares list object with caller.
}
/** Copy constructor */
public Wrong(Wrong wrong) {
this.list = wrong.list; // Error: now shares list object with caller.
}
public List<String> getList() {
return list; // Error: now shares list object with caller.
}
public void clear() {
list.clear();
}
}
コピー コンストラクターを使用してクラスを修正します。
public class Right {
private final List<String> list;
public Right(List<String> list) {
this.list = new ArrayList<>(list);
}
public Right(Right right) {
this.list = new ArrayList<>(right.list);
}
public List<String> getList() {
return new ArrayList<>(list);
}
public List<String> getListForReading() {
return Collections.unmodifiableList(list);
}
public void clear() {
list.clear();
}
}
テストコードを使用:
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
Collections.addAll(list1, "a", "b", "c", "d", "e");
Wrong w1 = new Wrong(list1);
list1.remove(0);
System.out.printf("The first element of w1 is %s.%n", w1.getList().get(0)); // "b"
Wrong w2 = new Wrong(w1);
w2.clear();
System.out.printf("Size of list1 %d, w1 %d, w2 %d.%n",
list1.size(), w1.getList().size(), w2.getList().size());
List<String> list2 = new ArrayList<>();
Collections.addAll(list2, "a", "b", "c", "d", "e");
Right r1 = new Right(list2);
list2.remove(0);
System.out.printf("The first element of r1 is %s.%n", r1.getList().get(0)); // "a"
Right r2 = new Right(r1);
r2.clear();
System.out.printf("Size of list2 %d, r1 %d, r2 %d.%n",
list2.size(), r1.getList().size(), r2.getList().size());
}
これにより、次のことが得られます。
The first element of w1 is b.
Size of list1 0, w1 0, w2 0.
The first element of r1 is a.
Size of list2 4, r1 5, r2 0.
オブジェクトのクローンを作成する必要がある場合は、Java のコピー コンストラクターを使用できます。
class Copy {
int a;
int b;
public Copy(Copy c1) {
a=c1.a;
b=c1.b;
}
}
c2=c1
あなたが Copy ;を与えるときのJavaで。コピーではなく元のオブジェクトへの参照を作成するだけなので、オブジェクトの値を手動でコピーする必要があります。
これを参照してください:
ここで、古いオブジェクトを渡し、その値をコピーして、新しいオブジェクトを作成します。
Color copiedColor = new Color(oldColor);
それ以外の :
Color copiedColor = new Color(oldColor.getRed(),
oldColor.getGreen(), oldColor.getBlue());
コピー コンストラクターは、既存のオブジェクトの値を使用して新しいオブジェクトを作成するために使用されます。
考えられる使用例の 1 つは、コピーされたオブジェクトを使用して作業できる一方で、元のオブジェクトが変更されないように保護することです。
public class Person
{
private String name;
private int age;
private int height;
/**
* Copy constructor which creates a Person object identical to p.
*/
public person(Person p)
{
person = p.person;
age = p.age;
height = p.height;
}
.
.
.
}
ディフェンシブ コピーに関連するこちらはよく読んでいます