Java 复制构造函数是否进行浅层复制?
我的问题很清楚。复制构造函数是否进行深度复制?还是肤浅的复制品 以下是我面临的情况: 我正在制作一个节点编辑器应用程序。我有一个抽象节点类。其中,我有一个名为Create()的抽象方法。我还以这种方式在所有子类中重写了该方法Java 复制构造函数是否进行浅层复制?,java,deep-copy,Java,Deep Copy,我的问题很清楚。复制构造函数是否进行深度复制?还是肤浅的复制品 以下是我面临的情况: 我正在制作一个节点编辑器应用程序。我有一个抽象节点类。其中,我有一个名为Create()的抽象方法。我还以这种方式在所有子类中重写了该方法 public Node Create(){ TestClass theTest = new TestClass(); theTest.Name = "Test Node"; theTest.Title = "Default Node";
public Node Create(){
TestClass theTest = new TestClass();
theTest.Name = "Test Node";
theTest.Title = "Default Node";
theTest.setSize(new Point2D.Float(250,200));
System.out.print(theTest.getClass());
return theTest;
}
我想这应该是一份深度拷贝。既然这样不行,我也试过了
public Node Create(Point2D location) {
TestClass theTest = null;
try {
theTest = this.getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
if (theTest != null) {
theTest.Name = "The Node";
theTest.Title = "Defaul Node";
theTest.setSize((new Point2D.Float(250,200)));
theTest.Location = location;
}
return theTest;
}
然后将所有子类类型添加到一个列表中,并使用子类创建一个弹出菜单。用户可以单击它并添加新节点。这是添加节点的代码。JMenuItem的MouseeEvent调用此方法
private void addNode(Node node){
Node newNode = node.Create(locationPersistence);
nodes.add(newNode);
}
但是没有运气。它似乎创建了一个浅拷贝而不是一个深拷贝。当我添加第一个节点时,它看起来很好。但当添加相同类型的第二个节点时,第一个节点将从该节点消失,并重新出现在新位置。这是否意味着这是一个肤浅的副本。如果是这样,如何实现深度复制?首先,默认情况下Java中没有复制构造函数。有一个
Cloneable
接口和clone()
方法。但默认情况下,该方法将生成浅拷贝
您的代码集链接到两个对象的属性
位置中相同的点2D
对象引用。您需要创建Point2D
对象的新实例,并在新对象中使用它。首先,默认情况下Java中没有复制构造函数。有一个Cloneable
接口和clone()
方法。但默认情况下,该方法将生成浅拷贝
您的代码集链接到两个对象的属性位置中相同的点2D
对象引用。您需要创建Point2D
对象的新实例,并在新对象中使用它。当您的类包含一个接受自身实例作为参数的构造函数时,就需要复制构造函数。该参数用于创建类的新实例,该实例的字段值与作为参数提供的实例类的字段值完全相同
您的节点类必须具有如下构造函数:
public class Node {
public Node(Node n) {
//copy all fields in Node n here
//eg this.a = n.a
//this.b = n.b etc
}
}
然后,当您从节点继承时,还需要在子类构造函数中调用此父方法:
public class TestClass extends Node {
public TestClass(TestClass t) {
super(t);
//copy any additional fields that is only present in TestClass here
}
}
现在,浅拷贝和深拷贝之间的区别。
浅复制是指将一个引用设置为另一个引用。
例如:
当您更改a的一个成员的值时,b也会受到影响。原因是a和b都是对同一对象的引用
a.x = 100;
System.out.println(b.x == 100); //prints true
如果a和b都引用它们自己的实例,那么深度复制就是。这可以通过以下方式完成:
Point2D a = new Point2D(50, 50);
Point2D b = new Point2D();
b.x = a.x
b.y = a.y
如果我现在键入:
a.x = 100
那么b.x将不会更改为相同的值,而是保留原来存储在a中的值,在本例中为50
System.out.println(b.x == 100); //prints false
System.out.println(b.x == 50); //prints true
如果您希望在构造函数中具有深度复制,那么您需要确保引用可变类的类的所有成员都引用自己的实例当您的类包含接受自身实例作为参数的构造函数时,复制构造函数就是。该参数用于创建类的新实例,该实例的字段值与作为参数提供的实例类的字段值完全相同
您的节点类必须具有如下构造函数:
public class Node {
public Node(Node n) {
//copy all fields in Node n here
//eg this.a = n.a
//this.b = n.b etc
}
}
然后,当您从节点继承时,还需要在子类构造函数中调用此父方法:
public class TestClass extends Node {
public TestClass(TestClass t) {
super(t);
//copy any additional fields that is only present in TestClass here
}
}
现在,浅拷贝和深拷贝之间的区别。
浅复制是指将一个引用设置为另一个引用。
例如:
当您更改a的一个成员的值时,b也会受到影响。原因是a和b都是对同一对象的引用
a.x = 100;
System.out.println(b.x == 100); //prints true
如果a和b都引用它们自己的实例,那么深度复制就是。这可以通过以下方式完成:
Point2D a = new Point2D(50, 50);
Point2D b = new Point2D();
b.x = a.x
b.y = a.y
如果我现在键入:
a.x = 100
那么b.x将不会更改为相同的值,而是保留原来存储在a中的值,在本例中为50
System.out.println(b.x == 100); //prints false
System.out.println(b.x == 50); //prints true
如果您希望在构造函数中具有深度复制,那么您需要确保引用可变类的类的所有成员都引用它们自己的实例Java避免深度复制
对于不可变字符串类,这没有问题,因为字符串可以共享
对于旧的可变java awt Point2D.Float类,one确实存在一个问题。用它代替不可变类可能比深度复制更好。
javafx.geometry.Point2D是不可变的
对于可变数组,存在一个问题。即使是final
数组也可以从外部更改其元素。这里的建议是使用集合
private final List<Point2D> points = new ArrayList<>();
public List<Point2D> getPoints() {
return Collections.unmodifiableList<>(points);
}
private final List points=new ArrayList();
公共列表getPoints(){
返回集合。不可修改列表(点数);
}
使用以小写字母开头的字段和方法名称的java约定。
Java在这方面非常严格
C/C++部分需要深度复制,以便将对象保留在本地堆栈上
Java在某种程度上消除了对复制构造函数的需要,但在历史上对字符串的使用是失败的:字符串有一个无意义的复制构造函数,可能是由intern()
和一个内部字符数组引起的。Java避免了深度复制
对于不可变字符串类,这没有问题,因为字符串可以共享
对于旧的可变java awt Point2D.Float类,one确实存在一个问题。用它代替不可变类可能比深度复制更好。
javafx.geometry.Point2D是不可变的
对于可变数组,存在一个问题。即使是final
数组也可以从外部更改其元素。这里的建议是使用集合
private final List<Point2D> points = new ArrayList<>();
public List<Point2D> getPoints() {
return Collections.unmodifiableList<>(points);
}
private final List points=new ArrayList();
公共列表getPoints(){
返回集合。不可修改列表(点数);
}
使用以小写字母开头的字段和方法名称的java约定。
Java在这方面非常严格