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.
Related
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
An abstract taken from Herbert Schildt book on Java
Cloning is a potentially dangerous action, because it can
cause unintended side effects. For example, if the object
being cloned contains a reference variable called obRef,
then when the clone is made, obRef in the clone will refer
to the same object as does obRef in the original.
If the clone makes a change to the contents of the object
referred to by obRef, then it will be changed for the original object, too.
So when the object is being cloned, do the references pointing to that
original object also gets cloned and as such these points to to the cloned object?
I am confused at this line "...obRef in the clone will refer
to the same object as does obRef in the original...".
Consider the difference between references to the original object, and references within the original object.
Suppose you have an object myObj of type MyClass which contains a field of type ArrayList named myList.
When you constructed this object, myList was initialized with new ArrayList() and is now pointing to an object in the VM's heap.
Now suppose you clone myObj
MyClass myClone = myObj.clone();
The variable myClone is pointing to a different object than myObj. They are two distinct objects. However, the myList field inside of myObj is pointing to the same object in the heap as myList in myClone. This is because when you clone, the references are copied as-is, there is no new ArrayList() that assigns a separate object to myList in the new object.
No references are ever changed automatically, so any references to your old myObj still point to it. The only reference you have to the new object is myClone until you assign it to additional variables. But the same is true for myList. So the two objects point to the same ArrayList. So if one of them adds to it, the other one sees the added values.
Normally, that's not what you need.
Lets say, I have a class called Another as shown :
public class Another {
int number;
String message;
// And so on.
}
And another class called CloneMe overriding clone() method ,as shown :
public class CloneMe {
int version;
Another another;
public CloneMe(int newVersion, Another obj) {
this.version = newVersion;
this.another = obj;
}
// and so on
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // You can also provide your own implementation here
}
}
Now, when you create an object of class CloneMe :
CloneMe actualObject = new CloneMe(10, new Another());
Then an instance of class Another is created and is assigned to reference another in your CloneMe class.
Now, when you call :
CloneMe clonedObject = actualObject.clone();
Then only a new instance of CloneMe is created with existing state of the actualObject. However, no new instance of any other class (for example, Another in our case) is created but the same object reference is assigned to the reference variable in the clonedObject. This is called shallow cloning.
If I have an instance of an object, and within that object is a variable that holds the data of another object. If I ever update the second object will the copy of that object be updated as well or do I need to simultaneously update all copies of said object.
For example:
public class Object()
{
int x = xValue;
Object linked = saidObject;
}
public class doStuff()
{
saidObject.x++;
if(linked.equals(saidObject))
return true;
}
will this code (not compilable obviously just fill in blanks) return true?
if(linked.equals(saidObject)) will return true as the two variables do point to the same object.
In Java all variables and fields are references to an actual Object that lives somewhere in memory.
When you assign one variable to another, it's like copying the address of the object so that they both point to the same object in memory.
e.g.
Object a = new Object(); // this actually creates the Object in memory
Object b = a; // this copies the reference to Object from a to b
// At this point, a and b point to exactly the same object in memory. Therefore ...
a.equals(b); // returns true.
In fact a == b returns true too, which is a better way of comparing for this case as == compares if two variables point to the same object (they do), whereas equals() often compares by value, which is unnecessary here.
It doesn't matter if b is actually a field within a (e.g. class Obj { Obj b; }; Obj a = new Obj(); a.b = a;) and it points to the same type of object, the principle is the same: a = b means they point to same object, nothing new is created.
By doing:
Object linked = saidObject;
you are not copying the object, just creating another pointer to it, it means you have two different pointers that point to the same object.
copying or cloning an object can be useful in some cases but its not the usual case.
An object instance is itself and is distinct from every other instance.
That is, mutating an object (by reassigning a field) someplace modifies it everywhere .. as, well, it is what it is. Likewise, mutating a different object .. is, well, changing a different object.
What is the difference between creating an object using the new keyword and creating an object using clone()? Is there any difference between memory allocation?
new creates an object according to the constructor, while clone() creates a new object and initializes the fields with the contents of the original object.
I take it, you read the javadoc, so let me take you through an example:
public class MyBaby implements Cloneable {
int age = 0;
String name = "Dolly";
List<String> list = new ArrayList<String>();
public static void main(String[] args) {
MyBaby originalBaby = new MyBaby();
originalBaby.setAge(1);
try {
// We clone the baby.
MyBaby clonedBaby = (MyBaby) originalBaby.clone();
// both babies now have: age 1, name "Molly" and an empty arraylist
originalBaby.setAge(2);
// originalBaby has age 2, the clone has age 1
originalBaby.setName("Molly");
// same goes for the String, both are individual fields
originalBaby.getList().add("addedString");
// both babies get the string added to the list,
// because both point to the same list.
System.out.println(clonedBaby.toString());
}
catch (CloneNotSupportedException e) {}
}
}
The javadoc says:
this method performs a "shallow copy" of this object, not a "deep
copy" operation.
which explains the behaviour of our babies' list: References are copied, not the elements that are referenced, thus our copy is "shallow"
The memory allocation can differ of course:
you can initialize fields in your constructor
clone can initialize a field, i.e. an array
new operator instantiates the new object while clone() is more like a copy constructor. clone() method creates a copy of the object with values of member attributes also copied.
Simple stated,
new creates an instance
while
clone returns a clone of an instance.
Clone() creates a new instance of the same class and copies all the fields to the new instance and returns it (shallow copying).
while the new keyword is a Java operator that creates the object ( http://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html ).
new() construcion of object as per default constructor.
clone() does shallow copy of references.
We should use clone only when the cost of object creation is high and we would rather clone and set the behaviour.
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();