問題:map拷貝時發現數據會變化。
高能預警,你看到的下面的栗子是不正確的,后面有正確的一種辦法,如果需要看的話的,請看到底,感謝各同學的提醒,已做更正,一定要看到最后
public
class CopyMap {
/**
*
@author 張仲華
*
@param args
* 2014 -8 -6 上午9:29:33
*/
public
static
void main(String[] args) {
Map<String,Integer> map =
new HashMap<String,Integer>();
map.put( "key1", 1);
Map<String,Integer> mapFirst = map;
System.
out.println( mapFirst);
map.put( "key2", 2);
System.
out.println( mapFirst);
}
}
|
深復制:被復制對象的所有變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量將指向被復制過的新對象,而不再是原有的那些被引用的對象。換言之,深復制把要復制的對象所引用的對象都復制了一遍。
public
class CopyMap {
/**
*
@author 張仲華
*
@param args
* 2014 -8 -6 上午9:29:33
*/
public
static
void main(String[] args) {
Map<String,Integer> map =
new HashMap<String,Integer>();
map.put( "key1", 1);
Map<String,Integer> mapFirst =
new HashMap<String,Integer>();
mapFirst.putAll(map); //深拷貝
System.
out.println(mapFirst);
map.put( "key2", 2);
System.
out.println(mapFirst);
}
}
|
參考:http://blog.csdn.net/lzkkevin/article/details/6667958
注意!!!注意!!!!注意!!! 上面並不是深拷貝,留下來的原因是提醒大家,這里是存在錯誤的。(很高興你看到這里了)
感謝下面這幾位朋友的提醒。
文章更正如下:
如何實現Map的深拷貝呢?
有一種方法,是使用序列化的方式來實現對象的深拷貝,但是前提是,對象必須是實現了Serializable接口才可以,Map本身沒有實現 Serializable 這個接口,所以這種方式不能序列化Map,也就是不能深拷貝Map。但是HashMap是可以的,因為它實現了 Serializable。下面的方式,基於HashMap來講,非Map的拷貝。
具體實現如下:
01 |
public class CloneUtils { |
02 |
03 |
@SuppressWarnings ( "unchecked" ) |
04 |
public static <T extends Serializable> T clone(T obj){ |
05 |
|
06 |
T clonedObj = null ; |
07 |
try { |
08 |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
09 |
ObjectOutputStream oos = new ObjectOutputStream(baos); |
10 |
oos.writeObject(obj); |
11 |
oos.close(); |
12 |
|
13 |
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); |
14 |
ObjectInputStream ois = new ObjectInputStream(bais); |
15 |
clonedObj = (T) ois.readObject(); |
16 |
ois.close(); |
17 |
|
18 |
} catch (Exception e){ |
19 |
e.printStackTrace(); |
20 |
} |
21 |
|
22 |
return clonedObj; |
23 |
} |
24 |
} |
如何使用呢,下面是個使用的例子,同時證明了Map的putAll方法並沒有實現深拷貝,putAll僅對基本數據類型起到深拷貝的作用。
栗子:
01 |
public static void main(String[] args) { |
02 |
|
03 |
List<Integer> list = new ArrayList<Integer>(); |
04 |
list.add( 100 ); |
05 |
list.add( 200 ); |
06 |
|
07 |
HashMap<String,Object> map = new HashMap<String,Object>(); |
08 |
//放基本類型數據 |
09 |
map.put( "basic" , 100 ); |
10 |
//放對象 |
11 |
map.put( "list" , list); |
12 |
|
13 |
HashMap<String,Object> mapNew = new HashMap<String,Object>(); |
14 |
mapNew.putAll(map); |
15 |
|
16 |
System.out.println( "----數據展示-----" ); |
17 |
System.out.println(map); |
18 |
System.out.println(mapNew); |
19 |
|
20 |
System.out.println( "----更改基本類型數據-----" ); |
21 |
map.put( "basic" , 200 ); |
22 |
System.out.println(map); |
23 |
System.out.println(mapNew); |
24 |
|
25 |
System.out.println( "----更改引用類型數據-----" ); |
26 |
list.add( 300 ); |
27 |
System.out.println(map); |
28 |
System.out.println(mapNew); |
29 |
|
30 |
|
31 |
System.out.println( "----使用序列化進行深拷貝-----" ); |
32 |
mapNew = CloneUtils.clone(map); |
33 |
list.add( 400 ); |
34 |
System.out.println(map); |
35 |
System.out.println(mapNew); |
36 |
|
37 |
} |
輸出結果如下:
最上面的兩條是原始數據,使用了putAll方法拷貝了一個新的mapNew對象,
中間兩條,是修改map對象的基本數據類型的時候,並沒有影響到mapNew對象。
但是看倒數第二組,更改引用數據類型的時候,發現mapNew的值也變化了,所以putAll並沒有對map產生深拷貝。
最后面是使用序列化的方式,發現,更改引用類型的數據的時候,mapNew對象並沒有發生變化,所以產生了深拷貝。
上述的工具類,可以實現對象的深拷貝,不僅限於HashMap,前提是實現了Serlizeable接口。
還沒有看putAll的源碼實現,后面看下為什么不能實現深拷貝。