Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/376.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 复制构造函数是否进行浅层复制?_Java_Deep Copy - Fatal编程技术网

Java 复制构造函数是否进行浅层复制?

Java 复制构造函数是否进行浅层复制?,java,deep-copy,Java,Deep Copy,我的问题很清楚。复制构造函数是否进行深度复制?还是肤浅的复制品 以下是我面临的情况: 我正在制作一个节点编辑器应用程序。我有一个抽象节点类。其中,我有一个名为Create()的抽象方法。我还以这种方式在所有子类中重写了该方法 public Node Create(){ TestClass theTest = new TestClass(); theTest.Name = "Test Node"; theTest.Title = "Default Node";

我的问题很清楚。复制构造函数是否进行深度复制?还是肤浅的复制品

以下是我面临的情况:

我正在制作一个节点编辑器应用程序。我有一个抽象节点类。其中,我有一个名为Create()的抽象方法。我还以这种方式在所有子类中重写了该方法

    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在这方面非常严格