Reputation: 19
My question is clear. Is a copy constructor make a deep copy? or a shallow copy?
Here is the situation I faced:
I'm making a node editor application. I've a abstract Node class. In that, I've abstract method called Create(). Also I overrode that method in all sub classes in this way,
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;
}
I thought this should make a deep copy. Since that didn't work, I tried this also.
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;
}
Then all the subclass types are added into a list and a popup menu is created with subclasses. User can click it and add a new node. This is the code to add a node. This method is called by a MouseEvent of the JMenuItem.
private void addNode(Node node){
Node newNode = node.Create(locationPersistence);
nodes.add(newNode);
}
But no luck. It seems to create a shallow copy instead of a deep copy. When I add the first node, it appears fine. But when adding a second node of same type, first node disappears from there and reappear at the new Location. Does this mean that this is making a shallow copy. If so, how to achieve a deep copy?
Upvotes: 0
Views: 1228
Reputation: 2036
A copy constructor is when your class contains a constructor that accepts an instance of itself as parameter. The parameter is used to create a new instance of the class that has the exact same values for its fields as the instance class that was provided as parameter.
Your Node class will have to have a constructor like this:
public class Node {
public Node(Node n) {
//copy all fields in Node n here
//eg this.a = n.a
//this.b = n.b etc
}
}
Then when you inherit from Node, you need to call this parent method in the child class constructor as well:
public class TestClass extends Node {
public TestClass(TestClass t) {
super(t);
//copy any additional fields that is only present in TestClass here
}
}
Now, difference between shallow and deep copy. Shallow copy is when a reference is set equal to another reference. Eg:
Point2D a = new Point2D(50, 50);
Point2D b = a;
When you change the value of one of a's members, b will also be affected. The reason is that both a and b is a reference to the same object.
a.x = 100;
System.out.println(b.x == 100); //prints true
Now deep copy is if both a and b refers to their own instances. This can be done as follows:
Point2D a = new Point2D(50, 50);
Point2D b = new Point2D();
b.x = a.x
b.y = a.y
If I now type:
a.x = 100
then b.x will not change to this same value, but keep the previous value that was originally store in a, in this case 50.
System.out.println(b.x == 100); //prints false
System.out.println(b.x == 50); //prints true
If you want to have deep copy in your constructor, then you need to ensure that all members of the class that are references to mutable classes, refer to their own instances
Upvotes: 0
Reputation: 109567
Java avoids deep copying.
For the immutable String class this is no problem, as Strings may be shared.
For the old mutable java awt Point2D.Float class one indeed has a problem. Substituting it for an immutable class would probably be better - than a deep copying. The javafx.geometry.Point2D is immutable.
For mutable arrays there is a problem. Even a final
array can have its elements changed from outside. Here the advise would be to use collections instead.
private final List<Point2D> points = new ArrayList<>();
public List<Point2D> getPoints() {
return Collections.unmodifiableList<>(points);
}
Use the java convention of field and method names starting with a small letter. Java is quite rigorous with respect to that.
C/C++ partly need deep copying for keeping objects on the local stack.
Java removed the need somewhat for copy constructors, but historically failed for String: String has a senseless copy constructor, probably instigated by intern()
and having an internal char array.
Upvotes: 0
Reputation: 8758
First, there is no such thing as copy constructor in Java by default. There is a Cloneable
interface and clone()
method. But that method by default will make shallow copy.
Your code sets link to the same Point2D
object references in property location
for both objects. You need to create new instance of Point2D
object and use it in new object.
Upvotes: 2