equals函数与hash计算
来源:互联网 发布:紫外线杀菌灯 知乎 编辑:程序博客网 时间:2024/06/06 02:53
应用场景
在Java中常用来判断两个对象是否相等的函数有equals和hashCode方法,最常见的就是在集合容器中,例如HashSet和HashMap中,保存两个不同的对象,所以需要提供一个合理的关于equals和hashCode的配置,以使得集合具有正确的使用性质。
示例
以典型的point为测试用例,为了保证集合中不存在两个相同(内容相同)的point,所以提供了重写的hashCode和equals方法
public class t{public static void main(String[] args){Set<point> arr=new HashSet<point>();point a=new point(1,2);point b=new point(1,2);arr.add(a);/*根据hashCode找到位置,非空则根据equals判断是否内容相等*/System.out.println("arr.contains(b): "+arr.contains(b));//返回truearr.add(b);Iterator<point> it=arr.iterator();while(it.hasNext()){/*输出"point a",map中key的hash值和equals方法都返回true只是替换value属性,对象节点不变*/point p=it.next();if(p==b){System.out.println("point b");}else if(p==a){System.out.println("point a");}}}}class point{private final int x;private final int y;public point(int x,int y){this.x=x;this.y=y;}public boolean equals(Object another){if(this==another){return true;}if(another instanceof point){point s=(point)another;return s.x==x&&s.y==y;}return false;}public int hashCode(){return x+y;}}
返回结果:
E:\>java tarr.contains(b): truepoint a我们知道HashSet使用的其实就是一个HashMap,所以在添加元素时,首先根据键值计算hash值,找到元素在table数组上的存储位置,然后利用equals函数判断该链表中是否内容相同的值,存在则替换值(只是替换值,对象不变)。
设计规范
所以关于equals和hashCode两个函数的要求如下:
1.equals返回相等的两个对象,hashCode返回值也要相等
2.hashCode返回相等的两个对象,equals不一定相等
第二条所说的也就是在使用HashMap中的碰撞问题,即发生碰撞则将节点放到table数组某个位置的Entry链表上(Entry节点包含一个Entry类型的next域)。
关于hashCode的返回值,由第一条内容可知,原则上要求hashCode要与equals保持一致。在Object中hashCode的方法为一个本地方法
/** As much as is reasonably practical, the hashCode method defined by * class {@code Object} does return distinct integers for distinct * objects. (This is typically implemented by converting the internal * address of the object into an integer, but this implementation * technique is not required by the * Java<font size="-2"><sup>TM</sup></font> programming language.) * * @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.System#identityHashCode */public native int hashCode();public boolean equals(Object obj) { return (this == obj); }equals方法结果是判断两个引用变量是否相等,判断引用变量中保存的对象地址或者对象的句柄地址是否相等,即判断是否引用的是同一个对象。由hashCode的方法描述可知,返回的是由对象的地址转换的整形变量。
Object中关于对象相等的判断过于严苛,在平时使用中,需要对这两个方法进行重写,例如Integer中的equals和hashCode判断的依据直接就是包装的int值
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }public int hashCode() { return value; }这里需要额外注意一点就是,更改一点代码如下:
public boolean equals(point another){if(this==another){return true;}if(another instanceof point){point s=(point)another;return s.x==x&&s.y==y;}return false;}即将point类中“重写”的equals方法参数类型做了一点修改
返回结果:
E:\>java tarr.contains(b): falsepoint bpoint a很明显此时属于方法重载,而不是重写或者覆盖。额外一句,方法名相同,参数【个数,顺序,类型】存在不同为重载,完全相同为重写/覆盖(返回值不同直接就是错误)。
因为对象的hashCode的随意性,所以hashCode值相等,equals不相等的情况很多(如果hashCode值相等,equals不等,则需要改函数了),也就是要求二中所说不一致。在map中处理碰撞的方式为建立链表,存储hash值(map中的hash值是根据hashCode的返回值又进行了一次hash运算,例如HashMap中table数组的长度为2的整数次幂,调整新的hash值与table数组长度减一,即高位全是0,低位全是1,进行与运算,使得元素随机分布在table数组中)相等的元素。
结论
上面所提到的所有关于hash值的计算,都是带有存储位置性质的计算,即为了解决对象的相等问题而添加的一种判断方式,与网络安全中所讨论的hash值属于完全不同的概念。虽然都做了相等判断,但是安全方面考虑的hash计算是指,提供一种实现能力上不可逆、不相等的哈希计算方法,即使hash值域有限,但是根据已知的hash值求出原始信息或者根据一个信息求出与之hash值相等的另一信息是不能实现的。
在普通应用中如果使用的hash值计算方式很简单的话,会存在安全风险,例如在提交表单数据时,默认将数据项存储在map表中,如果hash值的计算很简单的话,则恶意的攻击会导致map中存储的元素都在table中的一个位置上,形成一个长的链表,每次的存储会存在较大的查询性能,由散列表的O(1)变为O(n)(如果在链表过长时自动更改为红黑树,则为O(log n)),所以hash值计算方式不能设计的过于简单。
参考:http://coolshell.cn/articles/6424.html
- equals函数与hash计算
- hash code 与equals 区别
- GetHashCode Equals 与 Dictionary , Hash , List 的关系
- 多重hash与exists函数
- hash值的计算与转换
- "=="与equals,以及equals为ture时hash code是否相同
- hash值计算函数用于中文字符的错误纠正
- hash表和equals方法
- Hash函数与数字签名(数字手印)
- Hash函数与取模运算
- hash函数的设计思想与方法
- equals函数
- Hash 函数、Hash表
- python 计算hash值与java不一致问题
- hash函数
- hash函数
- hash函数
- hash函数
- echarts+ajax+restful实现图表(bar/line)
- 在MFC中获取控件相对位置和使按钮变灰
- 2、斐波那契数列以及青蛙跳台阶
- 单点登录的实现原理
- Fragment的初步用法
- equals函数与hash计算
- tjut 3061
- 存取之美 —— HashMap原理、源码、实践
- CSS after before 清除float
- OpenSceneGraph实现的NeHe OpenGL教程 - 第三十二课
- swift下面使用第三方Masonry 的代码
- GDB调试(一)
- IOS 调用第三方地图APP导航
- 地图标注表达式