23
ArrayList<Integer> a=new ArrayList<Integer>();
a.add(5);
ArrayList<Integer> b=(ArrayList<Integer>)a.clone();
a.add(6);
System.out.println(b.toString());

In the above piece of code, i think clone() does a shallow copy. So, b and a should point to the same memory location. However, when i do b.toString(), the answer is only 5. Why is 6 also not displayed if clone() does a shallow copy?

Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
TimeToCodeTheRoad
  • 7,032
  • 16
  • 57
  • 70
  • The same query here about the shallow copy: I expect it copied reference of an object type field and copied value of a primitive type field. https://stackoverflow.com/a/4592545/7375748 this answer helps, avoid clone(). I now let it go about when will it keep the same contents as the moment of copy and when will it updates automatically as the origin's update. – Woooody Amadeus Mar 31 '21 at 19:00

6 Answers6

55

Shallow copy does not mean that they point to the same memory location. That would be just an assignment:List b = a;.

Cloning creates a new instance, holding the same elements. This means you have 2 different lists, but their contents are the same. If you change the state of an object inside the first list, it will change in the second list. (Since you are using an immutable type - Integer - you can't observe this)

However, you should consider not using clone(). It works fine with collections, but generally it's considered broken. Use the copy-constructors - new ArrayList(originalList)

Jackson Chengalai
  • 3,907
  • 1
  • 24
  • 39
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 1
    so what is the difference between deep copy and shallow copy – TimeToCodeTheRoad Jan 04 '11 at 10:28
  • 1
    is it right to say that creating a clone of a list containing only mutable class objects, is a waste. – TimeToCodeTheRoad Jan 04 '11 at 10:30
  • 1
    @TimeToCodeTheRoad shallow copy works just like Bozho explained, deep copy copies the ArrayList and its elements. – João Portela Jan 04 '11 at 10:40
  • 2
    To just expand a little bit on what @JoãoPortela is saying, a deep copy results in all the objects being duplicated. You have a new container object, and all the objects inside are also duplicated. Note however, that objects contained within those objects (in the collection) may not be duplicated. You would have to make sure that every object is properly implementing a deep copy. If done correctly, you go from N objects to 2N objects. – thecoshman Jan 31 '14 at 15:38
  • It is two different lists but the second list will follow the changes on the first list? man, that's confusing. – Lendl Leyba Sep 25 '14 at 02:31
  • 1
    @LeiLeyba no, it's two separate lists, but the underlying objects will stay the same. That means if I retrieve some object `o` from list `a` and modify it, then it will have changed in all other places it's referenced, including list `b`. That does not mean that when I remove the reference to object o from list `a`, it will also be removed from list `b`. – Insomniac Apr 05 '15 at 18:09
7

If it was like you thought, then the clone method would be completely useless, because in that case, the following lines would be equivalent:

ArrayList<Integer> b = (ArrayList<Integer>)a.clone();
ArrayList<Integer> b = a;

Cloning is - like in real world scenarios - a process of creating two entities with exactly the same properties (at the time of the cloning operation).

And as Bozho mentioned - avoid the Java clone() concept. Even it's author mentioned, that it is broken.

This question and it's answers are quite valuable and provide a link to Josh Blochs own comments on his piece of work ;-)

Community
  • 1
  • 1
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
2

This indeed does a shallow copy, here is a comment for clone, from ArrayList source code

Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.)

To understand this, let's look at a snippet in clone method from ArrayList

v.elementData = Arrays.copyOf(elementData, size);

As we know, when we assign an Object to a variable, JAVA does not make a brand new copy of that Object. Instead, this variable becomes another reference pointing to the original Object.

Thus, elementData are actually storing reference to objects put into this ArrayList. And clone just copy these references, no replicas of Objects are created.

Of course, you can remove or add new reference to a cloned ArrayList.

However, modification of old Objects in one ArrayList will effect the original ArrayList. It's hard to do illustration with your example since Integer is immutable.

To see the side effect, you can define a custom mutable Object

class Person {
        private int a;

        public void setA(int a) {
            this.a = a;
        }
        public int getA() {
            return a;
        }
        @Override
        public String toString() {
            return String.valueOf(a);
        } 
   } 

Then you can use the following code to make test

        Person p1 = new Person();
        Person p2 = new Person();

        ArrayList<Person> tt = new ArrayList<Person>();
        tt.add(p1);
        tt.add(p2);

        ArrayList<Person> yy = (ArrayList<Person>) tt.clone();
        Person vv = yy.get(yy.indexOf(p2));
        vv.setA(12);
        yy.remove(p1);

        System.out.println("tt: " + tt);
        System.out.println("yy: " +yy);

The output should be

tt: [0, 12]
yy: [12]

See the side effect :) ? We only change the element in yy, but it is also reflected in tt.

user2473519
  • 191
  • 1
  • 4
1

Shallow Cloning is the default cloning strategy provided by Object.clone() which you are talking about. The clone() method of object class creates a new instance and copy all fields of the Cloneable object to that new instance (either it is primitive or reference). So in the case of reference types only reference bits gets copied to the new instance, therefore, the reference variable of both objects will point to the same object. The example we have seen above is an example of Shallow Cloning.

Deep Cloning As the name suggest deep cloning means cloning everything from one object to another object. To achieve this we need to trick our clone() method to provide our own cloning strategy. We can do it by implementing Cloneable interface and override clone() method in every reference type we have in our object hierarchy and then call super.clone() and these clone() methods in our object’s clone method.

But if you look at the clone() method of ArrayList in the source code, you will see it is externally copying v.elementData = Arrays.copyOf(elementData, size); after calling super.clone(), which means clone() of ArrayList deeply copies it content

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

To read more about Cloning and its types like deep cloning and shallow cloning please read Java Cloning and Types of Cloning (Shallow and Deep) in Details with Example

Naresh Joshi
  • 4,188
  • 35
  • 45
0

can't we select dynamically at what position we want to add the string like this

int r=k.nextInt();
Integer i6=new Integer(r);
System.out.println("Enter the address");
String p6=k.nextLine();
ar3.add(i6,p6);

its not excuting the after reading the integer

SztupY
  • 10,291
  • 8
  • 64
  • 87
vijay
  • 1
0

clone function in Arraylist is not same as copying one arraylist to another, If we use clone(), it holds the copy of original arraylist, but if we make any change to the original arraylist after use clone(), It will not affect the copyed arraylist.. Eg:

public static void main(String[] a) {

List list = new ArrayList();

list.add("A");

List list2 = ((List) ((ArrayList) list).clone());

System.out.println(list);
System.out.println(list2);

list.clear();

System.out.println(list);
System.out.println(list2);
}

Output:-

[A]

[A]

[ ]

[A]

Dahlia
  • 41
  • 11