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.
Related
I have a Model class defined in my project. and as usual it has some private variables and public getters and setters
public class Person{
private ArrayList<String> mark;
public void setMark(ArrayList<String> mark){
this.mark = mark;
}
public void getMark(){
return this.mark;
}
}
Suppose in some other class I am using this Model like
Person person = new Person();
ArrayList<String> mark = new ArrayList();
mark.add("10");
mark.add("15");
mark.add("18");
person.setMark();
then the private variable of person holds the value "my name", the I am accessing the variable using public getter of the class like
ArrayList<String> localMark = person.getMark()
so as per my knowledge person.getMark() returns the reference of private variable name, so if I modify the local variable 'localMark', then it will effect the private variable of Person class, so there it breaks the private property of the variable
ex:
ArrayList<String> localMark = person.getMark();
System.out.println(localMark.get(0)); // will be "10"
localMark.set(0,"25") // person.mark will be changed
System.out.println(person.getMark().get(0)); //will be printing "25"
most of the developers following the same design pattern I guess, but what is the correct way to create Models
EDIT
As per the comment of vinod I checked, and Strings it passes value but not reference but for ArrayList... it returns reference.
You have a reference (name) to an object instance (the value of name). As the reference is private, you're in full control of it.
When you return a reference, you in fact return it 'by value', meaning that a copy of the reference is returned. Both references point to the same value (the String instance)).
An outside caller obtaining the reference can assign a new value, but your model's own reference is unaffected by that and still points to the value.
It's like a dog (object) on a leash (reference).
When you return a reference you're returning a new leash onto the same dog.
The owner of the new reference can modify your dog (pet it, shave it, whatever) when the dog is mutable (which Strings are not, so it cannot be modified)
...or he can attach a new dog to his leash
...but he can never (reflection aside) attach YOUR leach to another dog.
If the instance being exposed by call to get() is mutable, then whatever changes you make in some other place will be reflected in the instance everywhere it is used.
Example :
methodX classA -
List<String> locaNamesList = person.getNamesList();
locaNamesList.clear();
Somewhere else
methodY classB -
List<String> locaNamesList = person.getNamesList(); // note the same person instance should be used.
//locaNamesList will be empty here
Just re-assigning the reference won' change anything.
List<String> locaNamesList = person.getNamesList();
locaNamesList = null; // won't change the actual list. You are setting local field locaNamesList to null and not the actual instance.
You have to use defensive-copies of mutable instances and pass them around if you don't want the original instance to be changed by external players (provided you can't make the instance itself immutable)
I am really confused about what is the difference between .clone() method or simply putting the = sign between objects while trying to clone it.
Thank You.
If you create a new Dog:
Dog a = new Dog("Mike");
and then:
Dog b = a;
You'd have one Dog and two variables that reference the same Dog. Therefore doing:
a.putHatOnHead("Fedora");
if (b.hasHatOnHead()) {
System.out.println("Has a hat: " + b.getHatName());
}
Will print that the dog has a Fedora hat, because a and b reference the same dog.
Instead, doing:
Dog b = a.clone();
Now you have two dogs clones. If you put a hat on each dog:
a.putHatOnHead("Rayden");
b.putHatOnHead("Fedora");
Each dog will have its own hat.
Let me try to explain you:
Object obj = new Object(); //creates a new object on the heap and links the reference obj to that object
Case 1:
Object obj2 = obj; //there is only one object on the heap but now two references are pointing to it.
Case 2:
Object obj2 = obj.clone(); //creates a new object on the heap, with same variables and values contained in obj and links the reference obj2 to it.
for more info on clone method, you can refer the java api documentation
The = sign is the assignment operator in java. Having a = b means "I assign to the variable a the value of variable b. If b is an object, then a = b makes a point to the object that b is pointing to. It does not copy the object, nor clone it.
If you want to clone an object you either have to do it by hand (ugly), or have to make the class that has to be clonable to implement Clonable then call clone().
The advantage on clone() over the "ugly" way is that with clone() it's the developer of the class to be cloned that defines how cloning has to be done in order to ensure that the copy is a legit and working copy.
With = you are just giving the same object a different name. With .clone you are creating a new object that is a copy of the original one.
= creates a new reference to the same object.
clone() creates a new physical object with the same attributes as the earlier one
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.
If I have a member variable such as this (declared in the body of a class)
private Dot[] dots=new Dot[numDots];
I loop through all members of this array, and:
1) Pass every Dot object to a function of another class, which:
2) Passes it to yet another function of a 3rd class, if some conditions are met
3) And the 3rd class changes some properties of the Dot object
then when this object is returned to the original/parent class, would those changes to its properties have retained? Or would it be treated like a local variable by the 2nd/3rd functions?
Yes, the changes to the properties are retained. Java is 100% pass-by-value, however, when you pass an object, the "value" passed is truly a pointer to the object. Thus, when you change an object in a method, you're changing the actual object passed in.
That is, if you have the following method, then the calling method will see the changes:
private void updateMyDot(final Dot aDot) {
aDot.dotColor = new Color(255,255,255);
}
but if you do the following, then the calling method will not see the changes.
private void updateMyDot(/* not final */ Dot aDot) {
aDot = new Dot();
aDot.dotColor = new Color(255,255,255);
}
In the second example, the caller will not see any changes and will not see the newly created Dot object.
Objects are passed by [reference value where the value is the reference] (things that inherit from Object), primitive values (int, long, double, etc.) are passed by value.
This means that when a primitive is passed from a caller to method it is copied, whereas with an object a [value of the] reference is passed.
Which in turn means that when an object is mutated by a method the caller sees those changes because it has a reference to the same object.
Conversely when a method mutates a primitive the caller does not see the changes as the method is working on a copy.
[reason for the edits]
If Java had pass by reference then you could do this:
Object x;
x = new Integer(42);
foo(x);
System.out.println(x.getClass()); // pass by reference would have it print out java.lang.Float
where foo is defined as:
void foo(Object o)
{
o = new Float(43);
}
Since Java passes the reference by value o = new Float(43); is allowed - but the value in the caller will remain as the new Integer(42);