`

Java 重写Object类中equals和hashCode方法

    博客分类:
  • Java
阅读更多

一:怎样重写equals()方法? 
  重写equals()方法看起来非常简单,但是有许多改写的方式会导致错误,并且后果非常严重。要想正确改写equals()方法,你必须要遵守它的通用约定。下面是约定的内容,来自java.lang.Object的规范: 
equals方法实现了等价关系(equivalence relation): 
1. 自反性:对于任意的引用值x,x.equals(x)一定为true。 
2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true时, 
  y.equals(x)也一定返回true。 
3. 传递性:对于任意的引用值x、y和z,如果x.equals(y)返回true, 
  并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。 
4. 一致性:对于任意的引用值x 和 y,如果用于equals比较的对象信息没有被修 
  改,多次调用x.equals(y)要么一致地返回true,要么一致地返回false。 
5. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false。 

 

二:重写equals方法的要点: 
1. 使用==操作符检查“实参是否为指向对象的一个引用”。 
2. 使用instanceof操作符检查“实参是否为正确的类型”。 
3. 把实参转换到正确的类型。 
4. 对于该类中每一个“关键”域,检查实参中的域与当前对象中对应的域值是否匹 
  配。对于既不是float也不是double类型的基本类型的域,可以使用==操作符 
  进行比较;对于对象引用类型的域,可以递归地调用所引用的对象的equals方法; 
  对于float类型的域,先使用Float.floatToIntBits转换成int类型的值, 
  然后使用==操作符比较int类型的值;对于double类型的域,先使用 
  Double.doubleToLongBits转换成long类型的值,然后使用==操作符比较 
  long类型的值。 
5. 当你编写完成了equals方法之后,应该问自己三个问题:它是否是对称的、传 
  递的、一致的?(其他两个特性通常会自行满足)如果答案是否定的,那么请找到 
  这些特性未能满足的原因,再修改equals方法的代码。

 

三:hashCode

hashCode主要是用于散列集合,通过对象hashCode返回值来与散列中的对象进行匹配,通过hashCode来查找散列中对象的效率为O(1),如果多个对象具有相同的hashCode,那么散列数据结构在同一个hashCode位置处的元素为一个链表,需要通过遍历链表中的对象,并调用equals来查找元素。这也是为什么要求如果对象通过equals比较返回true,那么其hashCode也必定一致的原因。

为对象提供一个高效的hashCode算法是一个很困难的事情。理想的hashCode算法除了达到本文最开始提到的要求之外,还应该是为不同的对象产生不相同的hashCode值,这样在操作散列的时候就完全可以达到O(1)的查找效率,而不必去遍历链表。假设散列中的所有元素的hashCode值都相同,那么在散列中查找一个元素的效率就变成了O(N),这同链表没有了任何的区别。

 

hashCode()的返回值和equals()的关系如下:

  • 如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。
  • 如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。
四.设计hashCode()
[1]把某个非零常数值,例如17,保存在int变量result中;
[2]对于对象中每一个关键域f(指equals方法中考虑的每一个域):
[2.1]boolean型,计算(f ? 0 : 1);
[2.2]byte,char,short型,计算(int);
[2.3]long型,计算(int) (f ^ (f>>>32));
[2.4]float型,计算Float.floatToIntBits(afloat);
[2.5]double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];
[2.6]对象引用,递归调用它的hashCode方法;
[2.7]数组域,对其中每个元素调用它的hashCode方法。
[3]将上面计算得到的散列码保存到int变量c,然后执行 result=31*result+c;
[4]返回result
 
这个算法存在这么几个问题需要探讨:
1. 为什么初始值要使用非0的整数?这个的目的主要是为了减少hash冲突,考虑这么个场景,如果初始值为0,并且计算hash值的前几个域hash值计算都为0,那么这几个域就会被忽略掉,但是初始值不为0,这些域就不会被忽略掉,示例代码:
 
01 import java.io.Serializable;
02  
03 public class Test implements Serializable {
04  
05     private static final long serialVersionUID = 1L;
06  
07     private final int[] array;
08  
09     public Test(int... a) {
10         array = a;
11     }
12  
13     @Override
14     public int hashCode() {
15         int result = 0//注意,此处初始值为0
16         for (int element : array) {
17             result = 31 * result + element;
18         }
19         return result;
20     }
21  
22     public static void main(String[] args) {
23         Test t = new Test(0000);
24         Test t2 = new Test(000);
25         System.out.println(t.hashCode());
26         System.out.println(t2.hashCode());
27     }
28  
29 }

 

如果hashCode中result的初始值为0,那么对象t和对象t2的hashCode值都会为0,尽管这两个对象不同。但如果result的值为17,那么计算hashCode的时候就不会忽略这些为0的值,最后的结果t1是15699857,t2是506447
 
2. 为什么每次需要使用乘法去操作result? 主要是为了使散列值依赖于域的顺序,还是上面的那个例子,Test t = new Test(1, 0)跟Test t2 = new Test(0, 1), t和t2的最终hashCode返回值是不一样的。
 
3. 为什么是31? 31是个神奇的数字,因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多。
分享到:
评论

相关推荐

    重写equals和hashcode方法_equals_重写equals和hashcode方法_

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中的两个核心方法,所有类都默认继承自Object类。这两个方法在处理对象比较和集合操作时起着至关重要的作用。当我们创建自定义类并需要对对象进行精确...

    关于Object中equals方法和hashCode方法判断的分析

    在 Java 中,Object 类提供了两个重要的方法:equals 方法和 hashCode 方法。这两个方法都是用于比较两个对象是否相等的,但它们的实现机理和作用域却有所不同。 equals 方法是用于比较两个对象是否相同的。它的...

    Java_重写equals()和hashCode()

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是对象的基本组成部分,它们在很多场景下都发挥着至关重要的作用。这两个方法与对象的相等性比较和哈希表(如HashMap、HashSet)的运作紧密相关。这篇博客将深入...

    Java重写equals及hashcode方法流程解析

    Java中的equals和hashCode方法是两个非常重要的方法,它们都是Object类中的方法。在实际开发中,正确地重写这两个方法对于确保程序的正确性和性能至关重要。下面,我们将详细地介绍Java重写equals及hashCode方法的...

    学习Object类——为什么要重写equeals和hashcode方法

    在 Java 编程语言中,Object 类是所有类的父类,但是在实际开发中,我们往往需要重写 Object 中的 equals 和 hashCode 方法,以便正确地比较对象的逻辑内容,而不是内存地址。下面我们将详细地解释为什么需要重写这...

    Java中equals,hashcode和==的区别

    "Java中equals、hashcode和==的区别" Java 中 equals、hashcode 和==的区别是 Java 编程语言中一个经常遇到的问题。这三个概念都是用来比较对象的,但是它们之间存在着本质的区别。 首先,==号是Java中的一个...

    关于重写equals,hashcode以及compareTo方法!

    equals()方法是Object类中的一个方法,它用于比较两个对象是否相等。然而,它的默认实现是比较对象的引用(地址),而不是比较对象的实际内容。因此,在某些情况下,我们需要重写equals()方法,使其比较对象的实际...

    equals与hashCode方法讲解

    equals 方法和 hashCode 方法是 Java 语言中两个重要的方法,它们都是在 Object 类中定义的。equals 方法用于比较两个对象是否相等,而 hashCode 方法用于返回对象的哈希码。 在 Java 的 Object 类中,equals 方法...

    Java中的equals和hashCode方法详解1

    总结来说,`equals()`和`hashCode()`是Java中用于对象比较和哈希存储的关键方法。它们的正确使用和重写对于确保对象比较的逻辑性和哈希表操作的效率至关重要。在自定义类中,应根据对象的属性和业务逻辑来重写这两个...

    equals与hashCode在实际开发中的重写写法

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是两个非常重要的成员,尤其是在处理对象比较和集合操作时。这两个方法通常与`Object`类中的默认实现相关联,但为了在实际开发中实现正确的对象比较和哈希表操作...

    Java容器集合(equals 和 hashCode+基础数据结构+ArrayList+Vector和LinkedList)

    hashCode方法是Java中用于计算对象的hash值的方法。在Object类中,hashCode方法是一个native方法,它返回对象的hash值。hashCode方法的目的是为了保证equals相同的两个对象的hashCode结果一致。 hashCode方法的实现...

    equals,hashcode,toString

    在这个类中,很可能已经重写了`equals()`, `hashCode()` 和 `toString()` 方法,以便更好地处理对象的比较、哈希存储和输出信息。 为了实现`DBObject`类的正确行为,开发者可能考虑了以下几点: 1. 在`equals()`...

    重写equals方法

    第一种情况:如果类中提供的 equals 方法无法满足需求,则需要重写 equals 方法。例如,在 String 类中,equals 方法用于比较两个字符串的内容是否相同,而不是比较它们的引用。 第二种情况:对于采用哈希算法的...

    重写hashCode()和equals()方法详细介绍

    在Java编程中,`equals()` 和 `hashCode()` 方法是Object类中的两个重要方法,它们在处理对象相等性以及在哈希表(如HashSet、HashMap)中起到关键作用。当自定义类时,有时需要根据业务逻辑重写这两个方法以满足...

    java中hashcode和equals的详解.pdf

    equals 方法是 Java 中一个非常重要的方法,因为它是 Object 类中的一个基本方法,每个对象都可以根据自己的需求来重写这个方法。 三、hashCode 和 equals 方法的关系 hashCode 和 equals 方法之间存在着紧密的...

    Java的Object类讲解案例代码 equals()、hashCode()、finalize()、clone()、wait()

    这个源码资源是关于Java中的Object类的讲解案例代码。Object类是所有Java类的根类,它定义了一些常用的方法,例如equals()、hashCode()、toString()等。本案例代码将详细展示Object类的使用方法,并提供一些实际场景...

    java中重写equals()方法的同时要重写hashcode()方法(详解)

    在 Java 中,重写 equals() 方法和 hashCode() 方法是非常重要的,它们可以确保对象的比较和标识正确。如果我们违反了这两个方法的规则,那么可能会产生理解的不一致。因此,在编写 Java 代码时,需要严格遵守这两个...

    探索Java中的equals()和hashCode()方法_动力节点Java学院整理

    Java中的equals()和hashCode()方法是两个重要的方法,它们都是从Object类中继承过来的。equals()方法用于比较两个对象的值是否相等,而hashCode()方法用于计算对象的哈希码。 equals()方法: equals()方法是用于...

    关于hashCode()和equals()的本质区别和联系

    在 Java 中,有很多类忽略了 hashCode() 和 equals() 方法的默认实现,以便提供更深层次的语义可比性。例如,Integer 类重写了 equals() 方法,使得两个 Integer 对象可以根据其整数值进行比较。这种基于值的 Equal ...

Global site tag (gtag.js) - Google Analytics