Does copy constructor makes a shallow copy? - java

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?

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.

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.

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

Related

Is there a difference in functionality when you use an intermediate variable during assignment?

I'm having trouble understanding what makes method A different from method B.
public class ListNode {
public String data;
public ListNode next;
public ListNode(String data, ListNode next) {
this.data = data;
this.next = next;
}
}
public void A(ListNode list, String name) {
ListNode asdf = new ListNode("hello", list);
list = asdf;
}
public void B(ListNode list, String name) {
list = new ListNode("hello", list);
}
No difference (functionally speaking).
Note that re-binding a method parameter is confusing because parameters in Java are passed by value, so when the method ends, list will be the same value as before the method call, no matter if you re-bind inside the method. This means your newly created ListNode object will have no strong reference and will be eventually garbage-collected.
For example:
final ListNode a = new ListNode("pre-call", list);
A(a, "Some name");
System.out.println(a.data); // Here it will print "pre-call" and not "hello"
Also it is usually considered a bad practice to re-bind parameters (kind of same as reusing variables). To avoid such mistakes I always declare method parameters as final.
The only difference is the readability of the two methods. Rest both the methods are doing the same thing
In method A the first reference is asdf for newly created ListNode object. this ' list = asdf' makes list as another reference to same ListNode object. Thus in method A there are two references for same object.
And the method B also does the same thing ie creates a new ListNode but this time using list as only reference.
Both methods achieve same thing but method A creates two references and assigns object to list indirectly while B on other hand directly uses list as a reference.

Reference new object through void method

I'm working on an assignment that deals with array manipulations for Java. Right now I have to delete elements inside the middle of an array. Now I know that arrays, once they're created cannot be changed in length. So I decided to make a new object, and have the former reference point to my new array.
public class A{
public static void main(String[] args){
B test = new B(val);
test.cut(2,4);
test.display();
}
class B{
private Obj[] array;
B(Obj val){
construct something
}
public void cut(int i, int j){
B newObject = new B(val);
...
newObject.array = this.array;
newObject = this;
}
}
The issue is that when I display the test object, it will only show me the original test object contents rather than newObject contents. Since this is a void method, I can't return an object. How do I reference the new object then? The last two lines for my cut method seem to have no effect at all. I know that ArrayList would be preferable for things like this, but this being a homework assignment we are forced to use arrays.
Now I know that arrays, once they're created cannot be changed in length.
This is true.
But the reference pointing to an array inside the B object instance can be changed (as you didn't declare it final):
public void cut(int i, int j){
Object[] newArray = new Object[len];
//... copying array content ...
this.array = newArray;
}
Beware of the thread safety issues such mutability causes. Mutable objects are usually frowned upon...
If the rules of assignment allow the use of class Arrays, this is what you can use instead of your own cut method:
newArray = Arrays.copyOfRange(oldArray, from, to);
In the method cut you create a new object of B then assign the the this reference to it. This has not effect as you have found because the this reference (the actual object) is not changed at all, The newObject is visible only inside this method, once it is terminated, the object is gone.
While you are in the same class B you dont have to create a new Object of it just for the purpose of altering the data it holds. You could just create a new array and copy the original content to it.
For copying the content you could use the method System#arraycopy. If you are not permited to use any jdk helping functionalities, then you could just loop over the original array and copy elements into the new one as you want.

shallow copy - new instance Or assignment

Shallow copy means a "copy" of an object with same values of their attributes whether primitive or reference values.
While performing shallow copy is it necessary to "create a new instance" ? as:
public class A {
int aValue;
B bObj;
...
public A createShallow(A a1Obj) {
A aObj = new A();
aObj.aValue = a1Obj.aValue;
aObj.bObj = a1Obj.bObj;
return aObj;
}
}
Or copy by assignment is also considered as shallow copy:
B b = new B(10);
A a = new A(1, b);
A a1 = a;
This article at wikipedia defines shallow copy as reference variables sharing same memory block. So according to this copy by assignment will also be a shallow copy.
But is not it a variables pointing to same object instead of "copy" of an Object ?
While performing shallow copy is it necessary to "create a new
instance" ?
Yes, you must create an instance to create a copy (either shallow or deep) of your object. Just doing the assignment of reference just creates a copy of reference which points to the same instance.
You have used a non-static method that is creating a copy. But generally I prefer two ways: -
Either use a copy-constructor: -
public A(A obj) {
copy.aValue = obj.aValue;
}
And use it like: -
A first = new A();
A copy = new A(first);
Or, use a public static method which takes an instance and returns a copy of that.
public static A createCopy(A obj) {
A copy = new A();
copy.aValue = obj.aValue;
return copy;
}
Assignment is not a copy - it's just a second reference to the same instance.
A copy must be a new instance, otherwise it isn't a copy; it's just another reference.
While performing shallow copy is it necessary to "create a new instance" ? as:
Yes, it is necessary.
Or copy by assignment is also considered as shallow copy:
No, this is a totally different operation. There is no copy; this simply creates a new reference to the existing object. If you modify the object through this new reference, you are still modifying the original object.
Reference assignment doesn't create a new object but just points to existing object.

Assigning value of an object to another - they mustn't point same adresses at memory

I have a problem with getting a new value of an object. I have a code like that:
...
TimeSchedule[] offspringScheduleOne = new TimeSchedule[AVAILABLE_CLASSROOMS];
...
offspringScheduleOne[i] = genes.get(geneOneIndex).getSchedule()[i];
...
After that assignment offspringScheduleOne[i] and genes.get(geneOneIndex).getSchedule()[i] points the same memory address. I want that: offspringScheduleOne[i] should get the value of the genes.get(geneOneIndex).getSchedule()[i], they musn't be same, they just should have same values.
TimeSchedule class:
public class TimeSchedule extends AlgorithmParameters {
public int[][] timetable = new int[DAYS][HOURS];//DAYS and HOURS are static final variables that comes from AlgorithmParameters
public int[][] getTimetable() {
return timetable;
}
public void setTimetable(int[][] timetable) {
this.timetable = timetable;
}
}
How can I do that?
It actually is copying the value - but you need to understand what that value is.
The value of offspringScheduleOne[0] isn't a TimeSchedule object. It's a reference to a TimeSchedule object. No expression in Java has a value which is an object. It's really important that you understand this.
Now, if you want a copy of the object, you'll have to make that happen yourself. For example, you could include a clone() method in TimeSchedule, and write:
offspringScheduleOne[i] = genes.get(geneOneIndex).getSchedule()[i].clone();
In other words, create a clone of the existing object, and then set offspringScheduleOne[i] to be a reference to that newly created object. Of course, if any of the fields within TimeSchedule is a reference type field, you'll need to consider whether or not you need to clone that object as well...
... or you could add a constructor and call that, or another method, etc. But you need to be absolutely clear that the assignment operator is copying the value, but that value is a reference.
EDIT: Okay, now that you've posted TimeSchedule, a few suggestions:
Stop using public fields. What's the point of having properties if the field is public?
Rather than having properties returning the whole array, change them to access an individual hour, e.g.
public int getTimetable(int day, int hour) {
// TBD: Argument validation
return timetable[day][hour];
}
// Similar for `setTimetable`
Create a clone method like this:
public TimeSchedule clone() {
TimeSchedule copy = new TimeSchedule();
for (int i = 0; i < timetable.length; i++) {
copy.timetable[i] = timetable[i].clone();
}
return copy;
}
(That's slightly wasteful in that it will create the subarrays and then discard them, but let's get something which works first...)
}
public Test clone() {
int[][] timetableCopy = new int[timetable.length][];
for (int i = 0; i < timetable.length; i++) {
timetableCopy[i] = timetable[i].clone();
}
return null;
}
You should create a new TimeSchedule object. Assuming you have a copy constructor you can use this:
TimeSchedule original = genes.get(geneOneIndex).getSchedule()[i];
TimeSchedule copy = new TimeSchedule(original);
offspringScheduleOne[i] = copy;
The constructor should copy the values from original. If you don't have such a constructor you can call get and set methods to copy the values across manually.
TimeSchedule original = genes.get(geneOneIndex).getSchedule()[i];
TimeSchedule copy = new TimeSchedule();
copy.setFoo(original.getFoo());
copy.setBar(original.getBar());
// etc...
offspringScheduleOne[i] = copy;
There's also a clone method that was designed for creating copies of objects, but it's awkward to use and it's probably best to avoid it.
You could let TimeSchedule override the clone method and write
offspringScheduleOne[i] = genes.get(geneOneIndex).getSchedule()[i].clone();

If you don't clone in Java then what do you do and what do you call it?

Does anyone have any suggested or established best practices and naming conventions for copy constructors / factory methods etc in Java? In particular, say I have a class Thing and I want a method somewhere that returns a new Thing with the same value as a Thing passed in (or as the instance if it's an instance method). Would you have this as constructor or a static factory method or instance method? What would you call it?
As per the title, I want to avoid clone() and Cloneable.
Effective Java recommends either of the following:
A copy constructor (as noted by others):
public Item(Item item)
A copy factory method:
public static Item newInstance(Item item)
(Also, no copying for immutables)
The primary difference is that with #1 you choose the actual class of the result, and with #2 the implementer can return a subclass. The semantics of the class may guide you into which one is best.
I would call it a copy method or a copy constructor (as the case may be). If it was a static method, then I would call it a factory.
In terms of what to do, the most flexible and long living option is a copy constructor. This gives subclasses the ability to copy themselves just like the parent.
I'd do a constructor
...
public Thing(Thing copyFrom)
{
attr1 = copyFrom.attr1;
attr2 = copyFrom.attr2;
//etc...
}
then when you want to clone it
Thing copy = new Thing(copy from me);
You can overwrite the clone()-method, if you want. Another used practice is a constructor, that takes an object of this type, i.e. new ArrayList(anotherList).
You've got a few options, implement Cloneable, add a copy constructor but my preferred way is to use a method (static or instance) that has a name which is descriptive of what the copy operation is doing - is it a deep or shallow copy, etc.
Use immutable data structures. The only reason you feel that you need clone() is that you're mutating your objects in place. Stop doing that. Think about how you can:
Make your classes final.
Make fields in your classes final and private.
For example, here's a "setter" for an immutable 3D vector object:
public Vector3D setX(double x) {
return new Vector3D(x, this.y, this.z);
}
So I guess what I'm saying is... I use copy constructors instead of mutation, and I just name them according to the attribute that I want to modify.
Another option is to implement the copying method in the source object, e.g.:
interface Has3DCoords {
void setLocation(double x, double y, double z);
void copyCoordsTo(Has3DCoords dest);
}
You would then implement copying with a piece of code like:
class Thing implements Has3DCoords {
private Point3D loc;
// ...
void setLocation(double x, double y, double z) {
loc.setLocation(x, y, z);
// or: loc = new Point3D(x, y, z);
}
void copyCoordsTo(Has3DCoords dest) {
loc.copyCoordsTo(dest);
// or: dest.setLocation(loc.getX(), loc.getY(), loc.getZ());
}
OtherThing createOtherThing() {
OtherThing result = new OtherThing();
this.copyCoordsTo(result);
return result;
}
}
This can be useful if:
It does not make sense to clone the whole object
There is a group of related properties that are often copied as one unit
You do not want to expose loc as a property of Thing
The number of properties is large (or there are many such groups) so a constructor that required all of them as parameters would be unwieldy.
This is not the nicest approach to copying objects but the following is sometimes useful if you wish to perform a deep copy of a Serializable object. This avoids having to write copy constuctors, implement Cloneable or writing factory classes.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
//Serializes the input object
oos.writeObject(input);
ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
//Copy of the input object
Object output = ois.readObject();
Don't forget to handle the exceptions and to close the streams nicely.

Categories