0

I want to do a backup copy of a Map (that contains other Maps). I have something like this:

Map<TYPE1, Map<TYPE2, TYPE3>>

TYPE1, TYPE2 and TYPE3 are objects from 3 different classes created by me (e.g the components of that classes are: String, Integer, Double,....)

I tried

Map<TYPE1, Map<TYPE2, TYPE3>> Map2= new HashMap<TYPE1, Map<TYPE2, TYPE3>>(Map1)
[....make some changings in Map1...]
Map1 = new HashMap<TYPE1, Map<TYPE2, TYPE3>>(Map2)

Map1 is the original Map I want to make a copy of. I also tried PutAll method but it didn't work (the content of the Map isn't the same of the original one).

Do you know other methods? Thank you.

  • Do you mean `Map2` is the original map you want to copy? If not, you've got your variables switched. – Steve Chaloner Nov 27 '15 at 10:35
  • How do you check the content of the map isn't the same as before? Note that order might be changed and the inner maps (values) should still be the same instances as before (they're not copied themselves, just the references to those maps). – Thomas Nov 27 '15 at 10:38
  • `Map1` is the original data, `Map2` is my backup. I copy `Map1` in `Map2`; – 5minutsOfBullfight Nov 27 '15 at 10:39
  • Also note that depending on what kind of changes you make to `Map1` after creating `Map2` (check Java naming conventions btw) they may or may not be visible after replacing `Map1` with a copy of `Map2`. – Thomas Nov 27 '15 at 10:40
  • Perhaps the changes you are making are *deep* changes. Your copy of the original map is only a shallow copy. It still refers to the same internal objects. – RealSkeptic Nov 27 '15 at 10:41
  • Your code just point the contents of map2 to contents in map1. – Roger Dwan Nov 27 '15 at 10:41
  • My goal is to have in Map1 the original data (that I will call from now "old data"), I call some functions that change the data so that "old data" becomes "new data". At the end of this process I want , again, in Map1 the "old data". How can I achieve this goal? – 5minutsOfBullfight Nov 27 '15 at 10:47

2 Answers2

0

Since the key and value in your collection are your self define class. Those content int the map are not really copied but share the same instance of your "TYPE". You need to do something like this to copy the value from all the content. This is just a very simple example, so there's no any encapsulation.

public class Foo1 {
    public Integer a = 0;

    public Foo1() {

    }

    public Foo1(Integer a) {
        this.a = a;
    }

    public Foo1 clone() {
        return new Foo1();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + getOuterType().hashCode();
        result = prime * result + ((a == null) ? 0 : a.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Foo1 other = (Foo1) obj;
        if (!getOuterType().equals(other.getOuterType()))
            return false;
        if (a == null) {
            if (other.a != null)
                return false;
        } else if (!a.equals(other.a))
            return false;
        return true;
    }
}

public class Foo2 {
    public Integer a = 0;

    public Foo2() {

    }

    public Foo2(Integer a) {
        this.a = a;
    }

    public Foo2 clone() {
        return new Foo2();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + getOuterType().hashCode();
        result = prime * result + ((a == null) ? 0 : a.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Foo1 other = (Foo1) obj;
        if (!getOuterType().equals(other.getOuterType()))
            return false;
        if (a == null) {
            if (other.a != null)
                return false;
        } else if (!a.equals(other.a))
            return false;
        return true;
    }
}

public class Foo3 {

    public Integer a = 0;

    public Foo3() {

    }

    public Foo3(Integer a) {
        this.a = a;
    }

    public Foo3 clone() {
        return new Foo3();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + getOuterType().hashCode();
        result = prime * result + ((a == null) ? 0 : a.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Foo1 other = (Foo1) obj;
        if (!getOuterType().equals(other.getOuterType()))
            return false;
        if (a == null) {
            if (other.a != null)
                return false;
        } else if (!a.equals(other.a))
            return false;
        return true;
    }
}

Copy your value by your own.

    Map<Foo1, Map<Foo2, Foo3>> map1 = new HashMap<Foo1, Map<Foo2, Foo3>>();
    Map<Foo1, Map<Foo2, Foo3>> map2 = new HashMap<Foo1, Map<Foo2, Foo3>>();

    Map<Foo2, Foo3> tmp = new HashMap<Foo2, Foo3>();
    tmp.put(foo.new Foo2(), foo.new Foo3());
    map1.put(foo.new Foo1(), tmp);

    for (Foo1 key : map1.keySet()) {
        Map<Foo2, Foo3> tmp2 = new HashMap<>();
        for (Foo2 key2 : map1.get(key).keySet()) {
            tmp2.put(key2.clone(), map1.get(key).get(key2).clone());
        }

        map2.put(key, tmp2);
    }
    for (Foo1 key : map1.keySet()) {
        for (Foo2 key2 : map1.get(key).keySet()) {
            map1.get(key).get(key2).a = 10;//change map1's value
        }
    }

    for (Foo1 key : map2.keySet()) {
        for (Foo2 key2 : map2.get(key).keySet()) {
            System.out.println(map2.get(key).get(key2).a);// the value in map2 still 0
        }
    }
Roger Dwan
  • 740
  • 4
  • 6
0

very interesting article about deep copy: How do you make a deep copy of an object in Java?

with serialization/deserialization, you dont need to go inside your classes, and you dont forget some variable. it gives:

Map<Integer, Map<String,String>> mimss =new HashMap<Integer, Map<String,String>>();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(mimss);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
Map<Integer, Map<String,String>> mimss_copy=(Map<Integer, Map<String,String>>) new ObjectInputStream(bais).readObject();

You can also convert to B64 in the middle if you want to save it in text:

         String serial= DatatypeConverter.printBase64Binary(byteData);
         byte[] byteData_reverse=DatatypeConverter.parseBase64Binary(serial);

REQUIREMENT: TYPE1, TYPE2, TYPE3 must be serializable

to be serializable, your class must be like that

public class myclass implements Serializable

and you should (not mandatory) declare inside

private static final long serialVersionUID = 6569838532917408380L;

If anything inside in serializable too, it's OK (standard types are, collections, ...)

Community
  • 1
  • 1