对元素是map的list进行深拷贝
1)先准备一个list,装有两个map,map的键值是基本数据类型
List list=new ArrayList<Map<String,String>>();
HashMap<String, String> map=new HashMap<String, String>();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
map.put("4", "four");
map.put("5", "five");
map.put("6", "six");
map.put("7", "seven");
map.put("8", "eight");
map.put("9", "nine");
map.put("10", "ten");
list.add(map);
HashMap<String, String> mapn=new HashMap<String, String>();
mapn.put("11", "one");
mapn.put("12", "two");
mapn.put("13", "three");
mapn.put("14", "four");
mapn.put("15", "five");
mapn.put("16", "six");
mapn.put("17", "seven");
mapn.put("18", "eight");
mapn.put("19", "nine");
mapn.put("20", "ten");
list.add(mapn);
方式一:
System.out.println("-----------------第1种方式(keySet遍历拷贝map基础类型)----------------------");
List list1=new ArrayList<Map<String,String>>();
for(int i=0;i<list.size();i++) {
HashMap<String, String> map1=new HashMap<String, String>();
HashMap<String, String> tmpMap=(HashMap<String, String>) list.get(i);
for(String key: tmpMap.keySet()) {
map1.put(key, tmpMap.get(key));
}
list1.add(map1);
}
((Map<String, String>) list.get(0)).put("1","newOne");
System.out.println(list);
System.out.println(list1);
方式二:
System.out.println("-----------------第2种方式(entrySet遍历拷贝map基础类型)-----------------------");
List list2=new ArrayList<Map<String,String>>();
for(int i=0;i<list.size();i++) {
HashMap<String, String> map1=new HashMap<String, String>();
HashMap<String, String> tmpMap=(HashMap<String, String>) list.get(i);
for(Map.Entry<String, String> entry: tmpMap.entrySet()) {
map1.put(entry.getKey(), entry.getValue());
}
list2.add(map1);
}
((Map<String, String>) list.get(0)).put("2","newTwo");
System.out.println(list);
System.out.println(list2);
方式三:
System.out.println("--------------------第三种方式(map对基本类型是深复制)---------------------");
List list3=new ArrayList<Map<String,String>>();
for(int i=0;i<list.size();i++) {
HashMap<String, String> tmpMap=(HashMap<String, String>) list.get(i);
// HashMap<String, String> map1=new HashMap<String, String>(tmpMap); 这个也可以
HashMap<String, String> map1=(HashMap<String, String>) tmpMap.clone();
list3.add(map1);
}
((Map<String, String>) list.get(0)).put("3","newThree");
System.out.println(list);
System.out.println(list3);
以上三种方式实则是一样的,区别就在于遍历或者复制map的方式不同。这里之所以加一个list套在外面,只是顺便提醒,list是引用类型,要深拷贝必须new 新的list.
由于map中存的是基本类型,所以上面三种方式都相当于进行了深复制。允许结果:
那么如果map中存的是引用类型,如何深复制
如果还采用上面的方式的话:
System.out.println("--------------------第4种方式(map对引用类型是浅复制)---------------------");
HashMap<String, Object> hashMap = new HashMap<>();
List<String> list4 = new ArrayList<>();
list4.add("math");
hashMap.put("list", list4);
Map<String, Object> mapCopy = new HashMap<>(); // 这里可以使用Map作为父类引用
mapCopy = (Map<String, Object>) hashMap.clone();
System.out.println(mapCopy);// {list=[math]}
list4.add("english");
System.out.println(mapCopy);// {list=[math]}
现在map中存的是list也就是一个引用类型了,采用前面的方法的话,结果:
看吧,发现改变原来的对象值,新的也会跟着改变。这也就是浅复制了。然后你也许会怀疑是clone方法的问题,认为如果遍历map赋值就不会,那么看下面:
System.out.println("--------------------第5种方式(map对引用类型是浅复制--getkey方式)---------------------");
HashMap<String, Object> hashMap5 = new HashMap<>();
List<String> list5 = new ArrayList<>();
list5.add("math");
hashMap5.put("list", list5);
Map<String, Object> mapCopy5 = new HashMap<>(); // 这里可以使用Map作为父类引用
for(String key :hashMap5.keySet()) {
mapCopy5.put(key, hashMap5.get(key));
}
System.out.println(mapCopy5);// {list=[math]}
list5.add("english");
System.out.println(mapCopy5);
运行结果:
如你所见,依然是浅复制。
那按照正常解决思路,当然就是想把map的value值也new 一个新的,就可以解决map的value值其实指向的是同一个地址的问题。解决办法:
System.out.println("--------------------第6种方式(map对引用类型进行深拷贝)---------------------");
HashMap<String, Object> hashMap6 = new HashMap<>();
List<String> list6 = new ArrayList<>();
list6.add("math");
hashMap6.put("list", list6);
Map<String, Object> mapCopy6 = new HashMap<>(); // 这里可以使用Map作为父类引用
for(String key :hashMap6.keySet()) {
List<String> listtmp = new ArrayList<>((List<String>) hashMap6.get(key));
mapCopy6.put(key, listtmp);
}
System.out.println(mapCopy6);// {list=[math]}
list6.add("english");
System.out.println(mapCopy6);//{list=[math]}
结果:
上面这一种不失为一种解决办法,但是还有一种使用起来比较简单的方法,就是利用序列化实现对象的深拷贝。:
System.out.println("--------------------第7种方式(使用序列化的方式来实现对象的深拷贝)---------------------");
// 注意不能使用Map<String, Object> map = newHashMap<>();不然CloneUtil.clone()方法报错,因为Map本身没有实现Serializable接口
HashMap<String, Object> hashMap7 = new HashMap<>();
List<String> list7 = new ArrayList<>();
list7.add("math");
hashMap7.put("list", list7);
Map<String, Object> mapCopy7 = new HashMap<>(); // 这里可以使用Map作为父类引用
mapCopy7 = CloneUtil.clone(hashMap7);
System.out.println(mapCopy7);// {list=[math]}
list7.add("english");
System.out.println(mapCopy7);// {list=[math]}
其中的工具类,可以创建一个,以后一劳永逸,源码如下:
public class CloneUtil {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) {
T cloneObj = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
}