博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于Object类的hashCode方法
阅读量:7223 次
发布时间:2019-06-29

本文共 4401 字,大约阅读时间需要 14 分钟。

hot3.png

####关于Object类的hashCode方法 //2016-08-19 16:00 在Object类的文档上是这么说hashcode()的.

The general contract of hashCode is: 1.Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

2.If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

3.It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

1.无论什么时候一个对象的hashcode方法被调用多少次, 只要那些被用于equals比较的信息没有改变.那么就应该是同样的结果.

2.如果两个对象通过***equals被认为相等,那么他们的hashcode也必须相等.***

3.如果两个对象被认为不equal,那么他们的hashCode***不用非得不相等***.


  • 第一条没什么可说的,但是第二三条却又是为什么呢?
  • 好比无序的Set集合是怎么知道内部元素有没有重复的呢?

通过看代码可以发现HashSet其实内部实现就是一个HashMap. 这里看一下contains方法的实现.

//java.util.HashSet.java transient HashMap
> backingMap; @Override public boolean contains(Object object) { return backingMap.containsKey(object); }//java.util.HashMap.javaOverride public boolean containsKey(Object key) { if (key == null) { return entryForNullKey != null; } int hash = Collections.secondaryHash(key); HashMapEntry
[] tab = table; for (HashMapEntry
e = tab[hash & (tab.length - 1)]; e != null; e = e.next) { K eKey = e.key; if (eKey == key || (e.hash == hash && key.equals(eKey))) { return true; } } return false;}

大致来说就是HashMap通过key的hashCode值来确定这个元素在内部存储的位置.

那么问题来了,根据文档上的规定***两个对象equals相等必须hashcode也相等***. 如果现在像这个情况,对象的equals相同但是hashcode不同会怎么样?

A.equals(B) && A.hashCode() != B.hashCode()

因为A.equals(B)你就认为A和B是一样的了.

map.put(A)map.get(A)map.get(B)
//java.lang.Object.java    public int hashCode() {     int lockWord = shadow$_monitor_;     final int lockWordMask = 0xC0000000;  // Top 2 bits.     final int lockWordStateHash = 0x80000000;  // Top 2 bits are value 2 (kStateHash).     if ((lockWord & lockWordMask) == lockWordStateHash) {         return lockWord & ~lockWordMask;     }     return System.identityHashCode(this); }// java.lang.System.java   public static native int identityHashCode(Object anObject);

注意如果你没重写对象的hashCode方法,那么它就是直接继承自Object类, 那么这里的map.get(B)就会返回null. 但是你明明已经put进map了(因为A.equals(B)) 所以为了避免这种蛋疼的情况, 你就应该保证两个对象equals相等那么hashcode也应该相等.

***如果两个对象被认为不equal,那么他们的hashCode不用非得不相等. ***

反过来看,即两个不equals的对象但是hashCode相同了. 也就是所谓的的hash碰撞. 下面以HashMap的代码来看看java是怎么处理这个问题的.

public V get(Object key) {        Node
e; return (e = getNode(hash(key), key)) == null ? null : e.value; } /** * Implements Map.get and related methods * * [@param](https://my.oschina.net/u/2303379) hash hash for key * [@param](https://my.oschina.net/u/2303379) key the key * [@return](https://my.oschina.net/u/556800) the node, or null if none */ final Node
getNode(int hash, Object key) { Node
[] tab; Node
first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { if (first instanceof TreeNode) return ((TreeNode
)first).getTreeNode(hash, key); do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; }static class Node
implements Map.Entry
{ final int hash; final K key; V value; Node
next;}

可以看到Node是一个单链表,如果发生hash碰撞了就需要挨个遍历. 但是如果没有hash碰撞,就可以直接返回. 所以应该尽可能的保证两个对象不一样,hashcode也不一样.

转载于:https://my.oschina.net/tanghaoo/blog/1842784

你可能感兴趣的文章
在Windows下建立QT开发环境
查看>>
Jedis、JedisPool、ShardedJedis和ShardedJedisPool,java对redis的基本操作
查看>>
[转载] 致命伴侣
查看>>
HTML5 localStorage本地存储实际应用举例
查看>>
Scala访问修饰符
查看>>
实习感悟
查看>>
产品经理网站小结
查看>>
Bootstrap 附加导航插件
查看>>
如何设置启动SMTP、POP3以及IMAP4的SSL服务端口?
查看>>
自制函数strcpy
查看>>
gSoap开发(三)——WSDL简介
查看>>
软件RAID5项目实战!!!
查看>>
Java基础学习总结(21)——数组
查看>>
js格式化日期
查看>>
定时与延时任务
查看>>
Squid 日志分析 和反向代理
查看>>
Hadoop的安装及一些基本概念解释
查看>>
大容量分区命令parted
查看>>
从输入 URL 到页面加载完成的过程中都发生了什么事情?
查看>>
实例讲解JQuery中this和$(this)区别
查看>>