复制构造函数和防御性复制
2022-09-02 09:30:59
什么是复制构造函数?
有人可以分享一个小例子,可以帮助理解以及防御性复制原理吗?
什么是复制构造函数?
有人可以分享一个小例子,可以帮助理解以及防御性复制原理吗?
这里有一个很好的例子:
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);
}
}
请注意构造函数如何获取 a 并复制它 - 这是一个 .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);
请注意,这不一定是创建对象的正确方法。但是,这是创建对象的好方法,可以确保您永远不会意外地对同一对象进行两次引用。显然,如果这是您想要实现的目标,那么这只是一件好事。
人们经常在C++中看到复制构造函数,其中部分隐藏的自动调用操作需要它们。
java java.awt.Point
并想到;也是非常旧的,可变的物体。Rectangle
通过使用不可变对象(如 、 或 ),只需分配对象引用即可。事实上,由于Java在C++之后的早期阶段,String中仍然有一个愚蠢的复制构造函数:String
BigDecimal
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.