浅析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() 之间的关系 三. 解密:深入理解 ...
随机推荐
- Android 一个漂亮的Android日期和时间选择器:DateTimePicker
DateTimePicker这个类库包含了漂亮的 DatePicker 和 TimePicker ,类似于在新 Google Agenda App中看到的. 项目主页:http://www.open- ...
- Epoll模型详解
Linux 2.6内核中提高网络I/O性能的新方法-epoll I/O多路复用技术在比较多的TCP网络服务器中有使用,即比较多的用到select函数. 1.为什么select落后 首先,在Lin ...
- [BS-12] JSON的基础知识--百科
JSON的基础知识--百科 http://baike.baidu.com/view/136475.htm
- Python模块 (psutil)
psutil psutil是Python中一个系统信息检索模块,可以获取(系统.CPU.内存.网络.磁盘)等信息,可以应用于系统的监控.健康状态检查,等同于shell中的ps.free.top.df功 ...
- markdown语法集锦
参考:http://wowubuntu.com/markdown/#blockquote 1. 标题 # 一级标题 ## 二级标题 ### 三级标题 共六级标题 2. 列表 有序列表:1,2,3: 无 ...
- js DOM 元素ID就是全局变量
有人在twitter上提到了:在Chrome的JavaScript终端中,你只需要输入一个元素的ID,就可以访问到这个元素.@johnjbarton给了解释,这是因为所有的元素ID都是全局变量.本文再 ...
- SVG 参考手册
1. SVG元素模块 Animation.Module animate animateColor animateTransform animateMotion set mpath 剪裁模块 clipP ...
- postgress Sql数据库的复制
1.保证本地可正常执行pg_dump,即就是本地有安装postgress数据库,最好把bin目录添加到环境变量path中2.在命令行中执行如下语句: pg_dump -U zhangsan -h 19 ...
- javascript学习之JSON
JSON本来是javascript的一个自己,后来已经成为了一种独立的数据格式,在web应用中运用极其广泛. 与javascript对象不同的是,JSON中的属性名任何时候都必须加双引号. javaS ...
- Error : L6218E: Undefined symbol downloadAddress (referred from nand.o).
MKD 报错: linking...LCD.axf: Error: L6218E: Undefined symbol EnZK (referred from ht128x64.o).LCD.axf: ...