什么是复制构造函数?
是否有人可以分享一个小例子,可以帮助理解与防御性复制原理
发布于 2013-02-22 09:45:02
下面是一个很好的例子:
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);
请注意,这并不一定是正确的创建对象的方式。然而,这是一种良好的创建对象的方法,可以确保您不会意外地拥有对同一个对象的两个引用。显然,如果这是你想要达到的目标,这才是一件好事。
发布于 2013-02-22 09:45:23
在C++中经常看到的复制构造函数是部分隐藏的、自动调用的操作所需的。
想到了java java.awt.Point
和Rectangle
;也是非常老的、易变的对象。
通过使用不可变对象(如String
或BigDecimal
),只需分配对象引用即可。事实上,由于Java在C++之后的早期阶段,字符串中仍然存在一个愚蠢的复制构造函数。
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.
发布于 2013-02-22 09:36:25
这是通过传递一个旧对象来创建一个新对象,复制它的值的地方。
Color copiedColor = new Color(oldColor);
而不是:
Color copiedColor = new Color(oldColor.getRed(),
oldColor.getGreen(), oldColor.getBlue());
https://stackoverflow.com/questions/15020850
复制相似问题