浅析Java的HashCode,以及equals
1.JDK规定,equals相等的两个对象hashCode也必须相等,这两个方法都是从Object上面继承而来的,通过观察JDK源码可以发现Object的equals方法是对2个对象的地址(逻辑地址,也就是在JVM中映射一个物理地址)比较,而hashCode又是一个本地方法,其实hashCode就是内存中的一个地址,换句话说,2个相等的对象(地址相等)那么他们的hashCode也肯定是相等的,反过来hashCode不相等,equals也一定不相等,但是hashCode相等equals却不一定相等,因为在生成hashCode的时候可能有冲突,还有一种情况就是JDK的String、Integer等等这些类都是重写了equals和hashCode方法的,不同的重写生成的hashCode有可能重复。
但是他们重写的结果依然是:equals相等,hashCode就相等(看源码得出的结论)。一般来讲重写equals都需要重写一下hashCode。
2.举例子:
有了上面的结论,那么举个简单的例子,Java的集合框架中的Set<E>是无序不能重复的,那么如何判断Set中的元素重复性就是equals的问题。
假设我们有一个User类:
public class User {
private String name;
private String password;
//get.set方法
}
现在把User的两个对象添加进一个Set<User>集合:
Set<User> sets = new HashSet<User>();
User u1 = new User("aaa", "aaa");
User u2 = new User("bbb", "bbb");
sets.add(u1);
sets.add(u2);
现在需要再向sets里面添加一个和u1一样的元素,User u3 = new User("aaa", "aaa");你会发现可以添加进去,这是怎么回事呢,u1和u3不是一样吗,其实不是这样的,u1和u3在内存中的地址不一样(分别new出来的两个对象地址不同),那么我们重写User的equals方法,如下:(我们只判断用户名,只要name相等就相等,忽视password)
@Override
public boolean equals(Object obj) {
if(obj == null) {
return false;
} if(!(obj instanceof User)) {
return false;
} if(this == obj) {
return true;
} User u = (User)obj;
if(!(this.name == null ? u.getName() == null : this.name.equals(u.getName()))) {
return false;
} return true;
}
再测试,发现u3还是能添加斤sets,这又是什么情况,不是说equals相等就是相同的元素,就不能添加进去吗,其实还有hashCode的原因。试想一下我现在sets里面只有u1和u2两个元素,当添加u3的时候,用u3跟u1和u2做equals比较,如果返回值为false就添加进去,如果为有一个为true就表示重复了,这样子是可行的,也是安全的,但是问题就在于如果我的sets里面已经有1w个User了呢,岂不是每一次添加新的User的时候都要比较1~10000次么,对于高并发的系统,这个是不允许的,性能太差。所以就有了hashCode,刚刚说道当sets里面存在u1和u2,当添加u3的时候,他要做遍历equals比较,其实Java不是这样做的,当添加u3的时候,JVM会先调用u3的hashCode方法,返回一个int数字,这个int数字上面说了,是映射一个内存地址,当sets在add u3的时候,他发现这块地址上面没有东西,那就直接添加进sets,不用比较,因为连内存中都不存在u3,那sets里面就肯定不存在了,根本不需要比较,但是,还有一种情况,就是当add u3的时候发现这块地址上面已经存在了一个u3,那是不是就意味着sets里面有u3了呢,答案是否定的,因为根据上面的规定,hashCode相等但是equals不一定相等,那么这时候就需要对sets里面的元素进行比较,如果返回值全都是false,就说明sets里面没有u3,那就添加进去,如果有一个返回值为true就说明已经存在了,就不添加进去,这样子性能就好很多。所以说就需要重写equals的同同时重写hashCode,并且保持一致性,前者相等,后者就必须相等,这是JDK规定,不然二者就没有什么意义了。于是重写hashCode,如下:
@Override
public int hashCode() {
return this.name.hashCode();
}
这样子就表示一个根据name重写,相同的name对应的hashCode一定是相同的。当比较到hashCode相同的时候直进行equals比较,而不同的时候直接添加。
这样一来,再添加name相同的两个User就一定添加不进去了。hashCode就是这样的原理。
浅析Java的HashCode,以及equals的更多相关文章
- java中hashcode()和equals()的详解
今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36). 1. 首先equals()和hashc ...
- 【Java】hashcode()和equals()
大家知道,在集合中判断集合中的两个元素是否相同,依赖的是hashcode()和equals()两个方法. > 一个简单的实验 public class Teacher { private Int ...
- Java中hashcode,equals和==
hashcode方法返回该对象的哈希码值. hashCode()方法可以用来来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的位置,Map在搜索一个对象的时候先通过has ...
- java中hashcode和equals的区别和联系
HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键. 那么Java运行时环境是如何判断HashSet中相同对象.Ha ...
- java 中hashcode和equals 总结
一.概述 在Java中hashCode的实现总是伴随着equals,他们是紧密配合的,你要是自己设计了其中一个,就要设计另外一个.当然在多数情况下,这两个方法是不用我们考虑的,直 ...
- java的HashCode和equals
什么时候用到hashcode,什么时候用到equals? 首先java为每个对象都生成有默认的hashcode,这个java core里说是java对象的内存地址,但是equals方法里比较的也是对象 ...
- 【JAVA】hashcode() & equals()
平时使用map时都是用JAVA原生的类型,所以很少关注到hashcode()和equals()的方法的内部实现.近期实现一个小工具,涉及到自己写的类的查找比对,又再次重温了相关的知识. 上简单示例代码 ...
- java中 hashCode() 和 equals()
1. 值类型是存储在内存中的栈,而引用类型的变量在栈中仅仅是存储引用类型变量的地址来自堆,而其本身则存储在栈中. 2. ==操作比较的是两个变量的值是否相等, 3. 对于引用型变量表示的是两个变量在堆 ...
- 深入探究Java中hashCode()和equals()的关系
目录 一.基础:hashCode() 和 equals() 简介 equals() hashCode() 二. 漫谈:初识 hashCode() 与 equals() 之间的关系 三. 解密:深入理解 ...
随机推荐
- 转 awk中RS,ORS,FS,OFS区别与联系
今天用到awk ofs 看到一篇不错文章 awk中RS,ORS,FS,OFS区别与联系 张映 发表于 2010-12-02 分类目录: shell 标签:awk, FS, OFS, ORS, RS, ...
- [BS] 小知识点总结-04
1. ios新知识学习思路: 在开发过程中如果遇到某种新需求以前从未做过,例如改变textField的Placeholder颜色,有如下思路和途径: 1.1 在Storyboard/Xib辅助编辑器A ...
- Android解决java.lang.OutOfMemoryError: bitmap size exceeds VM budget(转)
昨天遇到这个问题就是从一个输入流里调用BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri))得到一个bit ...
- Android之ScrollView嵌套ListView冲突
在ScrollView中嵌套使用ListView,ListView只会显示一行多一点.两者进行嵌套,即会发生冲突.由于ListView本身都继承于ScrollView,一旦在ScrollView中嵌套 ...
- 转: 利用 DEBUG_NEW 来追溯 Memory leak 内存泄漏
参考: https://msdn.microsoft.com/en-us/library/tz7sxz99.aspx http://www.cnblogs.com/taoxu0903/archive/ ...
- ios推送
1. ios 在杀掉app后,只能接受到系统通知,JPUSH自定义消息不能接受到.系统通知经过实验只能接收到50左右个汉字. 2. 实现方案: 推送的时候,JPUSH推送一个消息,App客户端获取到数 ...
- ajax请求后加额外的数据
$.ajax({ cache: true, type: "POST", url:"${ctx!}/bus/trail/getTrailInfoById", da ...
- 主机OS重装的节点加回RAC集群步骤示例(11gR2 RAC)
原文地址: https://blogs.oracle.com/Database4CN/entry/%E4%B8%BB%E6%9C%BAos%E9%87%8D%E8%A3%85%E7%9A%84%E8% ...
- Java基础之处理事件——使用动作Action(Sketcher 6 using Action objects)
控制台程序. 动作Action是任何实现了javax.swing.Action接口的类的对象.这个接口声明了操作Action对象的方法,例如,存储与动作相关的属性.启用和禁用动作.Action接口扩展 ...
- linux:网络yum源和制作本地光盘yum源
linux:存放yum源的位置:/etc/yum.repos.d/,该目录下全是一些yum源 一.网络yum源: 如图:下面全部都是yum源,后缀是".repo"都是合法的yum源 ...