关于Java中的HashMap的深浅拷贝的测试与几点思考
0、前言
工作忙起来后,许久不看算法,竟然DFA敏感词算法都要看好一阵才能理解。。。真是和三阶魔方还原手法一样,田园将芜,非常可惜啊。
在DFA算法中,第一步是需要理解它的数据结构,在此基础上,涉及到一些Hashmap的赋值。这里的赋值非常有趣,三个Hashmap翻来覆去赋值,就解决了敏感词表的初始化。
里面都是属于下文中的Hashmap“浅拷贝”,那么究竟Java中的Hashmap有哪些拷贝方法呢?
1、测试代码
HashMap hm_source = new HashMap();
HashMap hm_clone = new HashMap();
hm_source.put("1", "1"); // hashmap deep clone method 1
hm_clone = (HashMap)hm_source.clone();
// hashmap deep clone method 2
hm_clone.putAll(hm_source);// hashmap shadow clone
// hm_b = hm_a; hm_source.put("2", "2");
System.out.println("hm_source增加元素后,hm_source:"+hm_source);
System.out.println("hm_source增加元素后,hm_clone:"+hm_clone); System.out.println("是否指向同一内存地址:"+(hm_source==hm_clone));
System.out.println("第一个元素是否指向同一内存地址:"+(hm_source.get(1)==hm_clone.get(1)));
上面介绍了两种Hashmap深拷贝的方法,分别是hashmap.clone()和hashmap.putAll(hm_source),效果一样,输出如下:
hm_source增加元素后,hm_source:{1=1, 2=2}
hm_source增加元素后,hm_clone:{1=1}
是否指向同一内存地址:false
第一个元素是否指向同一内存地址:true
那么浅拷贝呢?(代码中注释的那段,直接等号=赋值),输出如下:
hm_source增加元素后,hm_source:{1=1, 2=2}
hm_source增加元素后,hm_clone:{1=1, 2=2}
是否指向同一内存地址:true
第一个元素是否指向同一内存地址:true
2、输出解析
不难发现,深浅拷贝确实如其名,
深拷贝:两个Hashmap对象似乎彻底无关,互相增加修改元素后,都不影响对方;
浅拷贝:两个Hashmap对象就是“软链接ln”,互相牵制,你改动了,我也跟着变。
3、上述猜想是否正确?
我党的思想路线是实事求是,预想剖析根本区别,大家可以看看JDK clone函数的源码。
但是从现象我们得到的初步结论有几点:
- 浅拷贝的两个对象使用的内存地址相同,深拷贝的对象地址“另立门户”;
- 深拷贝的两个对象也不完全“彻底无关”,仅仅是复制了元素的引用;
关于结论3.2,我也是在 HashMap的clone方法 博文中学习到了,里面使用的Hashmap元素是Bean类型的,深拷贝下的元素修改,也会“打断骨头连着筋”地让两个Hashmap同时更新。
但是仅限于“元素修改”,如若“元素增删”,那两个Hashmap对象就“翻脸不认人”了,不会同步更新。
4、hashmap.clone()
JDK是个难得的学习材料,源码还是要读的。现在也粘贴过来,做一些记录。
/**
* Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
* values themselves are not cloned.
* 【咱们中文叫“深拷贝”,老外美其名曰“拷贝一份实例的'浅拷贝'”,更加严谨】
* @return a shallow copy of this map
*/
@SuppressWarnings("unchecked")
@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();
result.putMapEntries(this, false);
return result;
}
/**
* Implements Map.putAll and Map constructor
*
* @param m the map
* @param evict false when initially constructing this map, else
* true (relayed to method afterNodeInsertion).
*/
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方法里面我初步扫了一下,也未涉及Hashmap instance对象的新建,是一些Hashmap结构中的Node的新建】
putVal(hash(key), key, value, false, evict);
}
}
}
以代码最终解释权由JDK1.8.x所有。
关于Java中的HashMap的深浅拷贝的测试与几点思考的更多相关文章
- 沉淀再出发:java中的HashMap、ConcurrentHashMap和Hashtable的认识
沉淀再出发:java中的HashMap.ConcurrentHashMap和Hashtable的认识 一.前言 很多知识在学习或者使用了之后总是会忘记的,但是如果把这些只是背后的原理理解了,并且记忆下 ...
- java 中遍历hashmap 和hashset 的方法
一.java中遍历hashmap: for (Map.Entry<String, Integer> entry : tempMap.entrySet()) { String ...
- Java中关于HashMap的元素遍历的顺序问题
Java中关于HashMap的元素遍历的顺序问题 今天在使用如下的方式遍历HashMap里面的元素时 1 for (Entry<String, String> entry : hashMa ...
- Java中关于HashMap的使用和遍历(转)
Java中关于HashMap的使用和遍历 分类: 算法与数据结构2011-10-19 10:53 5345人阅读 评论(0) 收藏 举报 hashmapjavastringobjectiterator ...
- [转]为什么Java中的HashMap默认加载因子是0.75
前几天在一个群里看到有人讨论hashmap中的加载因子为什么是默认0.75. HashMap源码中的加载因子 static final float DEFAULT_LOAD_FACTOR = 0.75 ...
- Java中的HashMap的工作原理是什么?
问答题23 /120 Java中的HashMap的工作原理是什么? 参考答案 Java中的HashMap是以键值对(key-value)的形式存储元素的.HashMap需要一个hash函数,它使用ha ...
- JAVA中JavaBean对象之间属性拷贝的方法
JAVA中JavaBean对象之间的拷贝通常是用get/set方法,但如果你有两个属性相同的JavaBean或有大部分属性相同的JavaBean,对于这种情况,可以采用以下几个简便方法处理. 下面对这 ...
- Java中的阻塞和非阻塞IO包各自的优劣思考(经典)
Java中的阻塞和非阻塞IO包各自的优劣思考 NIO 设计背后的基石:反应器模式,用于事件多路分离和分派的体系结构模式. 反应器(Reactor):用于事件多路分离和分派的体系结构模式 通常的,对一个 ...
- hash表及Java中的HashMap与HashSet
链接: http://alex09.iteye.com/blog/539545/ 当程序试图将一个 key-value 对放入 HashMap 中时,程序首先根据该 key 的 hashCode() ...
随机推荐
- QtGui.QProgressBar
A progress bar is a widget that is used when we process lengthy tasks. It is animated so that the us ...
- JQuery 之CSS操作
JQuery 之CSS操作 设置 <p> 元素的颜色: 将所有段落的颜色设为红色 $(".btn1").click(function(){ $("p" ...
- mindmanager2018优化
mindmanager2018优化 CreationTime--2018年6月6日09:35:02 Author:Marydon 1.点击“文件”-“选项”进入配置界面,在“常规”选项中,建议勾选 ...
- ubuntu系统——增加磁盘空间
1.df查看磁盘使用情况 2.将windows下的磁盘空间分出与部分给ubuntu 3.格式化磁盘 在终端输入:mkfs -t ext3 /dev/sdb1 用ext3格式对/dev/sd ...
- Hibernate基于注解方式的各种映射全面总结
1. 使用Hibernate Annotation来做对象关系映射 1) 添加必须包: hibernate-jpa-2.0-api-1.0.0.Final.jar 2) 在实体类中添加JPA的标准注解 ...
- 关于RDS备份文件使用wget下载提示403 Forbidden的情况
关于RDS备份文件使用wget下载提示403 Forbidden的情况 使用wget下载提示403错误当我们RDS物理备份文件时,例如: 原因: URL中包含有特殊字符比如&,从而造成URL被 ...
- 在where子句中经常使用的运算符
比较运算符 > < <= >= = <> 大于.小于.大于(小于)等于.不等于 BETWEEN ...AND... 显示在某一区间的值 IN ...
- 不止是联网!教你玩转PC自带Wi-Fi网卡
前言:Wi-Fi对于现在的智能手机来说已经是再熟悉不过的配置了,而主板自带Wi-Fi网卡的设计也越来越普及,但有些玩家可能思维还停留在“Wi-Fi网卡 = 连无线网络用的网卡,我用有线就不需要”的层次 ...
- Nginx+Windows负载均衡(转载)
一.下载Nginxhttp://nginx.org/download/nginx-1.0.8.zip解压到C:\nginx目录下二.在两台服务器上分别建一个网站:S1:192.168.16.35:80 ...
- Nginx an upstream response is buffered to a temporary file,nginx502错误
1.错误日志:warn:an upstream response is buffered to a temporary file 解决办法:增加fastcgi_buffers 8 4K; fa ...