什么是复制构造函数?
有人可以分享一个有助于理解防御性复制原则的小例子吗?
这是一个很好的例子:
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)
获取 aPoint
并对其进行复制 - 那是 a 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
浮现在脑海中;也是非常古老的可变对象。
通过使用不可变对象,例如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.
这是您通过传递旧对象并复制其值来创建新对象的地方。
Color copiedColor = new Color(oldColor);
代替 :
Color copiedColor = new Color(oldColor.getRed(),
oldColor.getGreen(), oldColor.getBlue());
复制构造函数用于使用现有对象的值创建新对象。
一种可能的用例是保护原始对象不被修改,而复制的对象可用于处理。
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;
}
.
.
.
}
与防御副本相关的这里是一个很好的阅读
当您需要克隆对象时,可以使用 java 中的复制构造函数
class Copy {
int a;
int b;
public Copy(Copy c1) {
a=c1.a;
b=c1.b;
}
}
在 java 中,当你给 Copy 时c2=c1
;只需创建对原始对象而不是副本的引用,因此您需要手动复制对象值。
看到这个: