关于java中的hashcode和equals方法原理
关于java中的hashcode和equals方法原理
1、介绍
java编程思想和很多资料都会对自定义javabean要求必须重写hashcode和equals方法,但并没有清晰给出为何重写此两个方法,至少不是非常的明确。
首先要确定的一件事是并不是“必须”,估计跟中英文语言习惯有关。hashcode方法只有在和hash类型的集合(比如HashMap和HashSet)配合使用时才会进行调用,否则是没有必要重写该方法的。
所以很多人会迷惑,自己并没有重写这方法,程序跑起来也没有问题。要说明这个问题必须要搞懂hashcode的真正作用以及使用场景。
2、hashcode
hashcode是java中Objet类定义的方法,默认返回的是对象的内存地址。但该方法的本意是散列。散列的话就必然涉及到在一定的空间中进行散列,所以hashcode方法一定是和集合配合使用的时候才用得到。
对象在空间散列化存储之后,其优势在于检索,如果散列算法处理得好,也就是能够保证对象在空间中尽可能均匀分布,则在检索时,一旦确定桶的方位(即下标值),就可以排除(n-1)/n的数据量,所有在大型数据集合中,hash之后的对象检索性能是非常高的。
java中的HashMap集合的内部实现是数组+链表实现,即Node[]数组方式实现的。而Node的源代码如下:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
说明Node节点类是一种手拉手实现的链表方式,而Node[]在java编程思想中称为桶集合,数组中每个元素可以看成一个桶。HashMap集合在初始化时会先分配16个桶的空间,在进行put操作时,会先将KV封装成Node对象,再对key进行计算,判断应该划分到哪个桶中。
注意key在集合中是“不重复”的,因此如果key存在,就将新的value替换掉旧的value,如果key不存在,就在链表的末尾进行添加。如何判断key是否重复?HashMap类中的putVal方法源码如下:请注意注释地方的判断条件是
p.hash == hash
&&((k = p.key) == key || (key != null && key.equals(k))),
首先明确p是KV构成Node对象,该对象源码中可见含有四个属性,分别是int hash、K key、V value和Node<K,V> next,其中hash并不是key中的hashcode,是对key的hashcode计算之后生成的新hash值,我们称为新哈希,而生成新hash的算法是:
int newhash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
翻译过来就是将旧哈希(我们称key对象的hashcode为就hash)向右移动16位之后和自身做异或运本意就是将高16位和低16位的值进行异或运算得到一个新的数值,这么做的意图非常明显,高位移位运算是想让更多的特征值参与进来,采用异或计算是想让数据更加分散。我们知道二进制位运算中有|、&、和~,很明显~是单元运算,如果采用|运算记录计算结果很大比例偏大,而采用&很大比例计算结果偏小,运算刚好高低比例相同。如此看来,设计也是非常巧妙的。
上面的判断条件翻译过来,就是:如果两个节点的新hash不同,则key一定不同。但如果新hash相同,还要判断key是否是同一对象,若是同一对象,则说明key相同,若不是同一对象,再判断equals方法是否相同。可以使用如下判断语句来描述获取更加清晰易懂:
if(newhash1 != newhash2){
//不同
}
else{
if(key1 == key2){
//相同
}
else{
if(key1.equals(key2)){
//相同
}
else{
//不同
}
}
}
桶的防止策略是对新hash对(桶数量-1)进行&运算产生的结果作为桶的下标值,由此可以看出,桶的数量一定是2的n次幂,默认是16只桶,即2^4次方,扩容以后会32,64以此类推下去。算法如下:
(n - 1) & hash //(16 - 1) & hash与取摸操作是等效的。
3、equals方法
equals方法比较简单,就是判断对象内容是否相同,默认实现是判断内存地址。在java的集合中,List并不判断对象hashcode值,只判断equals方法。
4、总结
java集合中,HashMap和HashSet使用hashcode进行对象的散列存储,因此会用到hashcode方法,自然也会用到equals方法,List集合只使用equals方法判断对象是否相等。
在java的集合中,真正的集合只有数组和链表两种实现,HashMap是通过两者组合实现的,而HashSet内部是通过HashMap实现的,丢弃了HashMap中的value部分,使用了一个垃圾值(dummy)进行填充实现的。
所以究其根本,ArrayList和LinkedList应该是最基本的集合,数组列表内部封装数组,擅长读操作,大量写入时(尤其是在队首插入数据)性能较差,因为需要移动所有元素,而LinkdedList在写入时非常有优势,查询则较差,两者各有优缺点,在使用单机进行百万数据读写的评测中,数组列表读取能是列表是进10倍,而列表的写入能力是数组列表的10倍以上,差距还是非常明显的。
关于java中的hashcode和equals方法原理的更多相关文章
- K:java中的hashCode和equals方法
hashCode和equals方法是Object类的相关方法,而所有的类都是直接或间接的继承于Object类而存在的,为此,所有的类中都存在着hashCode和equals.通过翻看Object类 ...
- java中的hashcode()和equals()
equals()和hashcode()都继承自object类. equals() equals()方法在object类中定义如下: public boolean equals(Object obj) ...
- Java中的hashCode() 和 equals()的若干问题解答
一.hashCode()的作用 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native int ...
- Java中的“==操作符”和equals方法有什么区别
Java中的"=="和equals方法究竟有什么区别? 1.==操作符 "=="操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的 ...
- Java 重写 hashCode() 和 equals() 方法
1. hashCode 1.1 基本概念 hashCode 是 JDK 根据对象的地址算出来的一个 int 数字(对象的哈希码值),代表了该对象再内存中的存储位置. hashCode() 方法是超级类 ...
- 有关java中的hashCode问题
1. HashSet集合存储数据的结构(哈希表) 1.1 什么是哈希表? 哈希表底层使用的也是数组机制,数组中也存放对象,而这些对象往数组中存放时的位置比较特殊,当需要把这些对象给数组中存放时,那么会 ...
- JAVA中的各种 哈希码(HashCode) 与 equals方法在HIBERNATE的实际应用[转载]
1.什么是哈希码(HashCode) 在Java中,哈希码代表对象的特征.例如对象 Java代码 String str1 = “aa”, str1.hashCode= 3104 String str2 ...
- Java 中正确使用 hashCode 和 equals 方法
在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...
- (转)Java 中正确使用 hashCode 和 equals 方法
背景:最近在编写持久化对象时候遇到重写equals和hashCode方法的情况,对这两个方法的重写做一个总结. 链接:https://www.oschina.net/question/82993_75 ...
随机推荐
- Forward链、Input链和Output链的区别
转载自:http://blog.chinaunix.net/uid-27863080-id-3442374.html 1. 如果数据包的目的地址是本机,则系统将数据包送往Input链.如果通过规则检查 ...
- adminLte 解决菜单栏 bug
<ul class="sidebar-menu" data-widget="tree"> 功能菜单 点击 不隐藏第三级 子菜单....在 ad ...
- Kibana6.2.2源码入口
后端入口 \kibana-6.2.2\src\server\kbn_server.js 前端入口 kibana-6.2.2\src\ui\public\chrome\chrome.js 页面框架模板 ...
- python爬取抖音APP视频教程
本文讲述爬取抖音APP视频数据(本文未完,后面还有很多地方优化总结) 公众号回复:抖音 即可获取源码 1.APP抓包教程,需要用到fiddler fiddler配置和使用查看>>王者荣耀盒 ...
- Problem02 输出素数
题目:判断101-200之间有多少个素数,并输出所有素数. 程序分析:判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除,则表明此数不是素数,反之是素数. public class ...
- idea各种快捷键
工作的的时候,如果不知道idea一些方便的快捷键会大大影响工作效率,今天打算看看这些小技巧: https://blog.csdn.net/linsongbin1/article/details/802 ...
- angularjs的ng-repeat回调
首先html代码是这样的: <label>Name des Leiters:</label><select name="leaderID" id=&q ...
- vue interceptors 设置请求头
在main.js添加过滤器,可以 Vue.http.interceptors.push((request,next)=>{ //request.credentials = true; // 接口 ...
- layui upload封装
<link rel="stylesheet" href="layui/css/layui.css"> <script src="js ...
- Murano Weekly Meeting 2015.09.22
Meeting time: 2015.September.22th 1:00~2:00 Chairperson: Serg Melikyan, PTL from Mirantis Meeting s ...