浅析Java的HashCode,以及equals
2014-04-01 17:10
316 查看
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类:
现在把User的两个对象添加进一个Set<User>集合:
现在需要再向sets里面添加一个和u1一样的元素,User u3 = new User("aaa", "aaa");你会发现可以添加进去,这是怎么回事呢,u1和u3不是一样吗,其实不是这样的,u1和u3在内存中的地址不一样(分别new出来的两个对象地址不同),那么我们重写User的equals方法,如下:(我们只判断用户名,只要name相等就相等,忽视password)
再测试,发现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,如下:
这样子就表示一个根据name重写,相同的name对应的hashCode一定是相同的。当比较到hashCode相同的时候直进行equals比较,而不同的时候直接添加。
这样一来,再添加name相同的两个User就一定添加不进去了。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中==、equals、hashcode的区别与重写equals以及hashcode方法实例
- java中的==、equals和hashCode以及hashCode生成
- Java基础之hashCode()的作用,以及==、equals()和hashCode()区别
- java中的== equals以及hashcode初步分析
- Java中equals()和hashCode()的关系以及重写equals()和hashCode()的重要性
- Java 中equal() 方法与==的区别以及 equals()与 hashCode()方法重写
- Java中的equals()、“==”以及hashCode()
- java中的==、equals和hashCode以及hashCode生成
- java中的==、equals和hashCode以及hashCode生成
- Java equals() 、hashCode()浅析
- java中hashCode方法与equals方法以及contains方法的用法总结
- 浅析Java中equals()方法和hashCode方法
- Java_hashCode()以及equals()方法浅谈
- java中的equals和hashCode方法以及集合的排序
- java中的==、equals和hashCode以及hashCode生成
- java的hashCode与equals以及HashMap元素确定
- java 重写HashCode和equals方法以及 HashMap集合 增 删 改 查
- 为什么要重写java中对象的equals方法和hashCode方法以及如何重写
- Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例
- java关于equals与==号的区别以及与hashCode的关系