博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于Java中的hashCode和equals方法
阅读量:5738 次
发布时间:2019-06-18

本文共 9380 字,大约阅读时间需要 31 分钟。

直接上源码!

public native int hashCode();
/**  * Returns a hash code value for the object. This method is  * supported for the benefit of hash tables such as those provided by  * {@link java.util.HashMap}.  * 

* The general contract of {@code hashCode} is: *

    *
  • Whenever it is invoked on the same object more than once during * an execution of a Java application, the {@code hashCode} method * must consistently return the same integer, provided no information * used in {@code equals} comparisons on the object is modified. * This integer need not remain consistent from one execution of an * application to another execution of the same application. *
  • If two objects are equal according to the {@code equals(Object)} * method, then calling the {@code hashCode} method on each of * the two objects must produce the same integer result. *
  • It is not required that if two objects are unequal * according to the {@link java.lang.Object#equals(java.lang.Object)} * method, then calling the {@code hashCode} method on each of the * two objects must produce distinct integer results. However, the * programmer should be aware that producing distinct integer results * for unequal objects may improve the performance of hash tables. *
*

* 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™ programming language.) * * @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.System#identityHashCode */

官方文档第一句话就说了,这个hashCode方法主要是为了哈希表而存在的,像HashSet,HashTable和HashMap都是使用哈希表的形式存储数据(Key Value),而hashCode计算出的hash值就可以唯一确定一个元素,有了hash值便可以快速定位元素,提高哈希表的性能。下面是hashCode规定的几点:

  • 在同一个Java应用程序中,只要是同一个对象,无论你调用hashCode方法多少次,它的返回值都应该是相同的。在不同的java应用程序中,这个返回值可以不同。
  • 如果两个对象通过equals方法判断出来是相同的,那么这两个对象调用hashCode方法的返回值也必须相同。
  • 如果两个对象通过调用顶级父类(Object)的equals方法判断出来是不相等的,那么这两个对象分别调用hashCode方法的返回值也必须是不同的。
  • 但是,作为程序员的我们可以在子类中重写这个方法,使得只要是对象中的值相等,那么这两个对象就相等,但是这可能会降低hash表的性能。(根据实际需求来判断是不是要重写吧)

基于这些原因,object类中的hashCode方法对于不同的对象必须返回不同的值(这是由内部转换方式决定的,通常这个值就是对象在JVM中的实际地址)

那这个值的取值肯定不都是对象实际所在的地址吧!比如说:8个基本数据类型的包装类的hashCode

  Boolean Byte Short Integer Long Character Float Doubles

下面我们来查看他们是怎么重写父类的方法的

  Boolean@Override

public int hashCode() {
return Boolean.hashCode(value); } /** * Returns a hash code for a {@code boolean} value; compatible with * {@code Boolean.hashCode()}. * * @param value the value to hash * @return a hash code value for a {@code boolean} value. * @since 1.8 */ public static int hashCode(boolean value) {
return value ? 1231 : 1237; } 可以看出,Boolean类型的变量,比较的是布尔值,如果都为true,那么返回1231,如果为false,那么返回1237,可以说只要 是Boolean类型的对象,只要值相同,那么他们就相同。

  Byte

@Override public int hashCode() {
return Byte.hashCode(value); } /** * Returns a hash code for a {@code byte} value; compatible with * {@code Byte.hashCode()}. * * @param value the value to hash * @return a hash code value for a {@code byte} value. * @since 1.8 */ public static int hashCode(byte value) {
return (int)value; } 对于Byte类型的对象,hashCode的值就是他强转为int类型后的值 Integer,Short同理都是转化为int类型后的值   Long
@Override public int hashCode() {
return Long.hashCode(value); } /** * Returns a hash code for a {@code long} value; compatible with * {@code Long.hashCode()}. * * @param value the value to hash * @return a hash code value for a {@code long} value. * @since 1.8 */ public static int hashCode(long value) {
return (int)(value ^ (value >>> 32)); }
返回值是其本身和他带符号右移后的数相异或得到的值再强转为int型。   Character 直接调用Object类的hashCode方法   Float
public static int hashCode(float value) {
return floatToIntBits(value); }
public static int floatToIntBits(float value) {
int result = floatToRawIntBits(value); // Check for NaN based on values of bit fields, maximum // exponent and nonzero significand. if ( ((result & FloatConsts.EXP_BIT_MASK) == FloatConsts.EXP_BIT_MASK) && (result & FloatConsts.SIGNIF_BIT_MASK) != 0) result = 0x7fc00000; return result; }public static native int floatToRawIntBits(float value);
API上这样说:返回这个浮点对象的哈希代码。其结果是整数位表示,与方法floatToIntBits(float)所产生的一样,是由这个 浮点对象表示的原始浮点的值   Double
与Floate型的差不多 API上这样说:返回此Double对象的哈希代码。结果是唯一的或两个半整数位表示的两个部分,完全由方法 doubleToLongBits(double)所产生

通过以上的这些话,可以很明确这个方法肯定和equals方法分不开。这不,源码中紧接着就是equals方法

public boolean equals(Object obj) {
return (this == obj); }
/**  * Indicates whether some other object is "equal to" this one.  * 

* The {@code equals} method implements an equivalence relation * on non-null object references: *

    *
  • It is reflexive: for any non-null reference value * {@code x}, {@code x.equals(x)} should return * {@code true}. *
  • It is symmetric: for any non-null reference values * {@code x} and {@code y}, {@code x.equals(y)} * should return {@code true} if and only if * {@code y.equals(x)} returns {@code true}. *
  • It is transitive: for any non-null reference values * {@code x}, {@code y}, and {@code z}, if * {@code x.equals(y)} returns {@code true} and * {@code y.equals(z)} returns {@code true}, then * {@code x.equals(z)} should return {@code true}. *
  • It is consistent: for any non-null reference values * {@code x} and {@code y}, multiple invocations of * {@code x.equals(y)} consistently return {@code true} * or consistently return {@code false}, provided no * information used in {@code equals} comparisons on the * objects is modified. *
  • For any non-null reference value {@code x}, * {@code x.equals(null)} should return {@code false}. *
*

* The {@code equals} method for class {@code Object} implements * the most discriminating possible equivalence relation on objects; * that is, for any non-null reference values {@code x} and * {@code y}, this method returns {@code true} if and only * if {@code x} and {@code y} refer to the same object * ({@code x == y} has the value {@code true}). *

* Note that it is generally necessary to override the {@code hashCode} * method whenever this method is overridden, so as to maintain the * general contract for the {@code hashCode} method, which states * that equal objects must have equal hash codes. * * @param obj the reference object with which to compare. * @return {@code true} if this object is the same as the obj * argument; {@code false} otherwise. * @see #hashCode() * @see java.util.HashMap */

直接比较两个对象是不是同一个对象

下面是重写equals方法需要满足的规则

  自反性:对于任何非空引用 x,x.equals(x) 应该返回 true

  对称性:对于任何引用 x 和 y,当且仅当 y.equals(x) 返回 truex.equals(y) 也应该返回 true

  传递性:对于任何引用 x、y 和 z,如果 x.equals(y)返回 truey.equals(z) 也应返回同样的结果

  一致性:如果 x 和 y 引用的对象没有发生变化,反复调用 x.equals(y) 应该返回同样的结果

  对于任意非空引用 x,x.equals(null) 应该返回 false

对于非空引用类型的变量,(在没有重写equals和hashCode的情况下)如果他们指向的在内存空间是同一个地址,那么他们就相等。重写equals方法最好也重写equals方法,主要的目的是保持和hashcode的关系(相同的对象必须拥有相同的hash值)。

重写了equals方法的几个包装类:File String Date 8个包装类,他们比较的都是类型及内容而不考虑引用是不是同一个对象,

如:

  String的equals方法

public boolean equals(Object anObject) {
if (this == anObject) {
return true; } if (anObject instanceof String) {
String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) {
char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) {
if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } 先比较是不是同一个对象,然后再比较长度,最后比较值,如果都满足相等,那么他们才是相等的

实例

public static void main(String[] args) {
String str1 = "BB"; String str2 = str1; String str3 = new String("BB"); String str4 = new String("BB"); System.out.println(str1==str2); System.out.println(str2==str3); System.out.println(str3==str4); System.out.println(str1.equals(str3)); System.out.println(str3.equals(str4)); }
结果:   true   false   false   true   true 现在来试试自定义的类   
public class Person {
Integer id; String name; } 这时我并没有重写equals方法
public static void main(String[] args) {
Person person1 = new Person(1, "小明"); Person person2 = new Person(1, "小明"); System.out.println(person1 == person2); System.out.println(person1.equals(person2)); } 结果:   false   false 当我重写父类的equals方法后 再打印一次   false   true 怎么重写equals和hashCode呢?

  大部分流行的几款ide都带有这个功能,当然也可以自己写,但是我就偷懒直接生成了

@Override public boolean equals(Object o) {
if (this == o) {
return true; } if (o == null || getClass() != o.getClass()) {
return false; } Person person = (Person) o; if (id != null ? !id.equals(person.id) : person.id != null) {
return false; } return name != null ? name.equals(person.name) : person.name == null; } @Override public int hashCode() {
int result = id != null ? id.hashCode() : 0; result = 31 * result + (name != null ? name.hashCode() : 0); return result; } 其中hashCode的返回值是自定义的,比如你可以将31改为32 Tips:了解过JVM后对这两个方法的理解会更透彻一点,结合源码食用

转载于:https://www.cnblogs.com/sunny-daylk/p/8994723.html

你可能感兴趣的文章
Spring Cloud版——电影售票系统<六>使用 Spring Cloud Config 统一管理微服务配置
查看>>
Java not support java EE1.3
查看>>
iptables规则备份及恢复、firewalld九个zone,service的操作
查看>>
www.conf配置文件的参数详解
查看>>
如何实现邀请好友帮抢票功能?
查看>>
深圳联通特邀湖北籍企业参观公司总部大楼举行
查看>>
告警系统主脚本、告警系统配置文件、告警系统监控项目
查看>>
Python 和 PyCharm 在 windows10 环境的安装和设置
查看>>
C语言入门基础之数组——数学和编程的完美结合(图)
查看>>
《远见》的读后感作文1000字范文
查看>>
重置密码、单用户模式、救援模式
查看>>
LAMP环境搭建1-mysql5.5
查看>>
第三课 Linux目录及文件管理、用户组管理及bash重定向
查看>>
shell 脚本攻略--小试牛刀
查看>>
spring boot view override
查看>>
bzoj 2282: [Sdoi2011]消防
查看>>
我的友情链接
查看>>
centos5.9使用RPM包搭建lamp平台
查看>>
关于C#面向对象2
查看>>
Javascript String类的属性及方法
查看>>