-
- 1. “=”赋值
-
2. 使用.putAll()方法
-
3. 使用.clone()方法
-
测试用例
-
测试用例源码
===================================================================
在我们最初使用map复制开发业务代码时,通常会踩到深浅复制(拷贝)这个坑里,比如我,在Map复制时
(如:Map<String, String> new_Map = old_Map) 出现过以下两类问题:
1.使用Map<String, String> new_Map = old_Map 操作,当修改new_Map属性后,old_Map属性也跟着变了,但我并没有修改过old_Map;
2.由于Map中的value值不仅有基本数据类型,还有引用数据类型,所以当我修改引用类型属性后,new_Map和old_Map的引用变量值都发生变化;(如你的value都是基本类型,就不涉及深浅拷贝的问题)
=====================================================================
新建一个Map,然后使用“=”直接赋值,这样只是复制了old_Map的引用,和old_Map仍使用同一个内存区域,所以,在修改new_Map的时候,old_Map的值同样会发生变化。
<Map<String, String> new_Map = old_Map>
上述的办法不行,使用Map本身提供的方法,网上大都说putAll()和clone()方法就是深拷贝,但是实际使用后,发现前后Map中的引用对象还是都被改变了;这里就是开头说到的,这两个方法只能修改基本数据类型的,如果是引用类型不行,这两个方法是浅拷贝!
来,让我们一起跟一下源码↓↓↓
创建一个新的Map结构,使用putAll()方法把原先的Map添加到新的Map中,但是发现修改了副本的Map之后,原先的Map中数据也被修改了;(源码如下)
public void putAll(Map<? extends K, ? extends V> m) {
putMapEntries(m, true); // 调用了putMapEntries方法
}
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
if (table == null) { // pre-size
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
if (t > threshold)
threshold = tableSizeFor(t);
}
else if (s > threshold)
resize();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict); // 循环调用了value,但value中的引用对象指针并没有改变。
// 扩展:map.put(“key”,“value”)的put()也是调用了putVal()方法
}
}
}
HashMap自带了一个clone()方法,但是,它的源码中注释说明了也只是一种浅复制(拷贝):(源码如下)
@Override
public Object clone() {
HashMap<K,V> result;
try {
result = (HashMap<K,V>)super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn’t happen, since we are Cloneable
throw new InternalError(e);
}
result.reinitialize(); // 清空map
result.putMapEntries(this, false); // 可见,和putAll调用了同一个接口,
return result;
}
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
if (table == null) { // pre-size
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
if (t > threshold)
threshold = tableSizeFor(t);
}
else if (s > threshold)
resize();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict); // 同上,循环调用了“value”,value中的引用对象指针并没有改变
}
}
}
===================================================================
List list = new ArrayList();
list.add(100);
list.add(200);
HashMap<String,Object> old_map = new HashMap<String,Object>();
old_map.put(“name”, “蔡虚坤”);//放基本类型数据
old_map.put(“list”, list);//放对象
HashMap<String,Object> new_map = new HashMap<String,Object>();
new_map.putAll(old_map);
System.out.println(“----基础数据展示-----”);
System.out.println("old: " + old_map);
System.out.println("new: " + new_map);
System.out.println(“----更改基本数据类型的数据-----”);
old_map.put(“name”, “娘炮”);
System.out.println("old: " + old_map);
System.out.println("new: " + new_map);
System.out.println(“----更改引用类型的数据-----”);
list.add(300);
System.out.println("old: " + old_map);
System.out.println("new: " + new_map);
System.out.println(“----使用序列化进行深拷贝 自定义Clone方法-----”);
new_map = myClone(old_map); // myClone() 方法源码在下方 ↓↓
list.add(400);
System.out.println("old: " + old_map);
System.out.println("new: " + new_map);
输出结果:
Connected to the target VM, address: ‘127.0.0.1:58242’, transport: ‘socket’
----基础数据展示-----
old: {name=蔡虚坤, list=[100, 200]}
new: {name=蔡虚坤, list=[100, 200]}
----更改基本数据类型的数据-----
old: {name=娘炮, list=[100, 200]}
new: {name=蔡虚坤, list=[100, 200]}
----更改引用类型的数据-----
old: {name=娘炮, list=[100, 200, 300]}
new: {name=蔡虚坤, list=[100, 200, 300]}
----使用序列化进行深拷贝-----
old: {name=娘炮, list=[100, 200, 300, 400]}
new: {name=娘炮, list=[100, 200, 300]}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
06)]
[外链图片转存中…(img-0m70ipvD-1715532388506)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!