关于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() ...
随机推荐
- Python 小程序,对文件操作及其它
以下是自己写的几个对文件操作的小程序,里面涉及到文件操作,列表(集合,字典)的运用等.比方说,从文件里读取一行数据.分别存放于列表中,再对列表进行操作.如去掉里面的反复项.排序等操作. 常见对文件里行 ...
- 基于canvas的仪表盘效果
概述 基于Canvas实现的仪表盘及效果.通过配置参数,可以任意修改仪表盘颜色,刻度,动画过渡时间等,满足不同场景下的使用.同时使用原生的Canvas,也是学习Canvas的很好的例子. 详细 代码下 ...
- 转:Mosquitto用户认证配置
转自:https://blog.csdn.net/u012377333/article/details/69397124?utm_source=blogxgwz1 前言:基于Mosquitto服务器已 ...
- nyoj 37 回文字符串 【DP】
先反向复制一个新的字符串,然后再找出最长公共子串,在用长度n减去就可以 回文字符串 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描写叙述 所谓回文字符串,就是一个字符串,从 ...
- WinForm下的键盘事件(KeyPress、KeyDown)及如何处理不响应键盘事件
KeyDown事件用来处理功能键:F1 F2 F3... keyPress事件用来处理字符比如说:A B C... 1 2 3... 注:处理该事件时,需要先将窗体的 KeyPreview=true; ...
- leetcode难度及频率
1 Two Sum 2 5 array sort set Two Pointers 2 Add Two Numbers 3 4 linked l ...
- js 字符串拼接 html 累加 html 叠加
正常来说已经使用es6 的 模板了如`` //页面层 layer.open({ type: 1, content:`<div class="child_card"> & ...
- [Jobdu] 题目1377:缓变序列
题目描述: 陈博在写论文时碰到一个难题:如何将给定的整数序列变换成缓变序列:即任意两个相邻的元素相差均为1,第1个元素和最后一个元素相差也为1. 变换是指改变原整数序列中各元素的顺序.例如整数序列1, ...
- QT类之------QLabel
QLabel 类代表标签,它是一个用于显示文本或图像的窗口部件. 构造 QLabel 类支持以下构造函数: [plain] view plaincopy QLabel(QWidget *parent ...
- Linux安装Scala步骤
1.到官方下载tgz的安装包. http://www.scala-lang.org/download/ 注意:在最下面的Other Resources中 2.下载后将压缩包放在/usr/local目录 ...