再谈HashMap-由一个实际问题引发的对HashMap设计吐嘈
来源:互联网 发布:网络p2p的四条红线 编辑:程序博客网 时间:2024/06/05 01:14
前言
这一篇主要想讲一讲HashMap在设计上的缺陷以及在使用的过程中留下的一些隐患。也是在实际项目中可能需要注意的一些地方。比如说我下面要介绍的一个containsKey方法,以及List里面其实有一个toArray[]方法返回的是一个Object[]数组的,其实都不是很好用的一种设计,在泛型里有点不伦不类的感觉。
项目背景
事情的起因是在项目中因为漏改可能引起的一个故障想起的。这里大概介绍一下整个过程:有这样一种场景,定义了一个HashMap<Integer,Long>类型的变量,Key是Integer类型的,后来因为某些原因把这个变量改成了HashMap<Long,Long>,这里注意一下这个Key,由Integer变成Long类型,讲到这里还没有什么问题。问题出在哪里,代码里面有一个逻辑是需要判断里面的Key是否存在(也就是会调用containsKey(Object key)这个方法),但是这里因为某些原因传的值仍然是Integer类型的。问题就出来了,这样会发现从HashMap是拿不到value的,结果就是containsKey()这样一个方法后返回的是false。接下来会用一个实例来还原这样我上面所说的场景:
实例
- public static void main(String[] args) {
- Map<Long,Long> map = new HashMap<Long,Long>();
- map.put(new Long(1), new Long(1));//这里的key是Long类型
- Integer key = new Integer(1);
- boolean result = map.containsKey(key);//这里的key是Integer类型
- System.out.println(result);
- }
先看一看输出结果,没错,是false,没有任何疑问,这里可以看看HashMap是如何查找value的:HashMap会先比较key的hashCode,然后会直接比较这个key值是否相等(== || equals),这里可以参考我另一篇文章《HashMap源码分析》。下面我把HashMap获取Entry的方法给贴出来,重点看一下里面查找Key的方式。
- final Entry<K,V> getEntry(Object key) {
- int hash = (key == null) ? 0 : hash(key.hashCode());
- for (Entry<K,V> e = table[indexFor(hash, table.length)];
- e != null;
- e = e.next) {
- Object k;
- if (e.hash == hash &&
- ((k = e.key) == key || (key != null && key.equals(k))))
- return e;
- }
- return null;
- }
接着我把Integer和Long的equals方法贴出来,看看这两个类对于equals方法的实现,这样就可以比较清晰的知道为什么在HashMap中containsKey如果里面本来存的key是Integer类型,而调用containsKey传的值是Long类型后得到的结果是false。
Integer的equals方法
- public boolean equals(Object obj) {
- if (obj instanceof Integer) {
- return value == ((Integer)obj).intValue();
- }
- return false;
- }
Long的equals方法
- public boolean equals(Object obj) {
- if (obj instanceof Long) {
- return value == ((Long)obj).longValue();
- }
- return false;
- }
吐槽
讲到这里估计有些人有疑问了。上面讲的有什么问题吗?这些大家都知道啊。这不是最基本的知识点吗?等等,好戏才刚刚开始。这里注意看一下HashMap中containsKey这个方法(下面是源代码):
- public boolean containsKey(Object key) {
- return getEntry(key) != null;
- }
- public boolean containsKey(K key) {
- return getEntry(key) != null;
- }
总结
上面我从一个实例入手来讲用HashMap中遇到的一些坑,反映出HashMap设计不完美之处。这样设计其实也有一些无奈之举,这也是因为HashMap的泛型是JDK 1.5引入的,为了让之前的版本得到比较好的兼容才保留了之前原有的接口。最后讲到一个设计原则就是能把问题留在编译器就不要把问题留在运行期,越早发现越好。再讲讲最上面那个项目的事情,幸好这个问题发现了,不然后果将会非常严重,心有余悸。 0 0
- 再谈HashMap-由一个实际问题引发的对HashMap设计吐嘈
- 再谈HashMap-由一个实际问题引发的对HashMap设计吐嘈
- 再谈HashMap-由一个实际问题引发的对HashMap设计吐嘈
- 一个异常引发的对Hashtable和HashMap的思考
- 由面试引出我对HashMap的理解
- 由一个小程序引发对 size_type类型的思考
- HashMap的设计理念
- 一个简易的HashMap
- HashMap设计原理、HashMap的数据结构、HashMap源码实现
- Hashtable与HashMap引发的血案
- 一个对hashmap线程安全分析的博客
- 如何自己设计一个高效类似于HashMap的容器
- 对HashMap的value排序
- 说说对HashMap的理解
- 对HashMap的“操”作
- hashmap对字符串的统计
- hashmap 设计
- 一个学生对HashMap源码注释分析
- Spring3.0.5+Mybatis3.0.5+Struts2.0.6整合
- HashMap之equals与hashCode小陷阱
- 深入Java单例模式
- 关于商享网
- 内核怎样管理你的内存
- 再谈HashMap-由一个实际问题引发的对HashMap设计吐嘈
- java 初级对象问题
- 11.1
- zTree实现地市县三级级联Action类
- javascript深入理解js闭包
- HashMap源码分析
- UML 使用
- 串(C++实现)
- UML-活动图(Activity Diagram)