Search code examples
javacloneshallow-copy

why shallow copy on Hashmap is not reflecting


I have created the map added few items and clone to demonstrate shallow copy. after cloning I added a new item into old reference but item was not reflected into new reference.

public class Test implements Cloneable {

    public static void main(String[] args) {
        HashMap<String,String> smap  = new HashMap<String,String>();
        smap.put("a1","a1");
        smap.put("a2","a2");
        smap.put("a3","a3");
        smap.put("a4","a4");

        //SHALLOW COPY 
        HashMap<String,String> cMap = (HashMap)smap.clone();
        cMap.put("b1","bb");


        smap.put("a5","55");

        System.out.println("orignal_map\t"+smap);
        System.out.println("cMap\t"+cMap);

        HashMap<String, String> scopyx = new HashMap<String, String>(smap);
        System.out.println("S_copy_x:\t"+scopyx);

    }
}

Solution

  • Shallow copying means that it is not applied to copying objects inside the original objects. That is, if you have an object containing a collection and you clone this object, the collection itself is not copied and may become shared between multiple instances:

    public class Test implements Cloneable {
        private List<String> innerList = new ArrayList<>();
    
        public void addBaz(String baz) {
            innerList.add(baz);
        }
    
        public List<String> getInnerList() {
            return innerList;
        }
    
        public void setInnerList(List<String> innerList) {
            this.innerList = innerList;
        }
    
        public static void main(String[] args) throws CloneNotSupportedException {
            Test bar1 = new Test();
            bar1.addBaz("baz1");
            bar1.addBaz("baz2");
            bar1.addBaz("baz3");
    
            System.out.println("bar1 before cloning: " + bar1.getInnerList());
    
            Test cloneBar = (Test) bar1.clone();
    
            System.out.println("clone: " + cloneBar.getInnerList());
    
            bar1.addBaz("baz4");
            System.out.println("clone after adding to original: " + cloneBar.getInnerList());
    
            cloneBar.addBaz("cloneBaz1");
            System.out.println("bar1 after adding to clone: " + bar1.getInnerList());
        }
    }
    

    The output is:

    bar1 before cloning: [baz1, baz2, baz3]
    clone: [baz1, baz2, baz3]
    clone after adding to original: [baz1, baz2, baz3, baz4]
    bar1 after adding to clone: [baz1, baz2, baz3, baz4, cloneBaz1]
    

    Also, if you had added to the HashMap other object than String, you could see, that shallow copy works there too - the original and cloned map contain shared objects and therefore contents of both maps may change:

    public class Test implements Cloneable {
        private String foo;
    
    // getter/setter/toString ...
    
        public static void main(String[] args) {
            HashMap<String, Test> map = new HashMap<>();
            map.put("a1", new Test("a1"));
            map.put("a2", new Test("a2"));
            map.put("a3", new Test("a3"));
    
            System.out.println("map before cloning: " + map);
    
            HashMap<String, Test> cmap = (HashMap<String, Test>) map.clone();
    
            System.out.println("clone: " + cmap);
    
            map.put("b1", new Test("b1"));
            System.out.println("clone after adding to original: " + cmap);
    
            cmap.put("c1", new Test("c1"));
            System.out.println("original after adding to clone: " + map);
    
            map.get("a1").setFoo("new a1");
            System.out.println("clone after modifying object inside original: " + cmap);
    
            cmap.get("a2").setFoo("cloned a2");
            System.out.println("original after modifying the clone: " + map);
        }
    }
    

    The output is:

    map before cloning: {a1=->a1, a2=->a2, a3=->a3}
    clone: {a1=->a1, a2=->a2, a3=->a3}
    clone after adding to original: {a1=->a1, a2=->a2, a3=->a3}
    original after adding to clone: {a1=->a1, a2=->a2, a3=->a3, b1=->b1}
    clone after modifying object inside original: {a1=->new a1, a2=->a2, a3=->a3, c1=->c1}
    original after modifying the clone: {a1=->new a1, a2=->cloned a2, a3=->a3, b1=->b1}