如何正确的覆盖equals和hashCode

一、Object所有的非final方法

  1. public boolean equals(Object obj)
  2. public native int hashCode()
  3. public String toString()
  4. protected native Object clone() throws CloneNotSupportedException
  5. protected void finalize() throws Throwable { }

类的方法前加final关键字,说明该方法不能被该类的子类重写。

二、equals方法和hashCode方法

1、什么时候需要覆盖equals方法

如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时候我们就需要覆盖equals方法。

2、如何正确的覆盖equals方法

equals方法实现了等价关系:自反性,对称性,传递性,一致性,非空性(x.equals(null)返回为false

  • 使用==操作符检查“参数是否为这个对象的引用”,如果是,则返回true。
  • 使用instanceof操作符检查“参数是否为正确的类型”,如果不是,则返回false。
  • 把参数转换成正确的类型。
  • 对于该类中的每个“关键”阈,检查参数中的阈是否与该对象中对应的阈相匹配。
class Student{

    private String name;
    private int age;
    private double height;
    @Override
    public boolean equals(Object obj) {
        //使用==操作符检查“参数是否为这个对象的引用”
        if(this==obj)
            return true;
        //使用instanceof操作符检查“参数是否为正确的类型”
        if(!(obj instanceof Student))
            return false;
        //把参数转换成正确的类型。
        Student student=(Student) obj;
        //对于该类中的每个“关键”阈,检查参数中的阈是否与该对象中对应的阈相匹配。
        return  this.name==student.name && this.age==student.age && this.height==student.height;
    }
}

1、编写完成equals方法之后,应该问自己三个问题:它是否对称的、传递的、一致的。

2、不要将equals声明中的Object对象替换为其他的类型

public boolean equals(Student obj)

这样相当于重载了equals方法,而非是覆盖。

3、覆盖equals时总要覆盖hashCode

HashCode有一条约定如下:

如果两个对象根据equals(Object)方法比较是相等,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。

下面给出一种简单的解决办法:

  1. 把某个非零的常数值,比如说17,保存在一个名为result的int类型的变量中。
  2. 对于对象每个关键域f(指equals方法中涉及的每个域),完成以下步骤:
    1. 如果该域是boolean类型,则计算(f ? 1 : 0)。

      private boolean flag=true;
      int boolTemp=flag?0:1;
    2. 如果该域是byte、char、short或者int类型,则计算(int)f。
    3. 如果该域是float类型,则计算Float.floatToIntBit(f)。
    4. 如果该域是long类型,则计算(int)(f ^ (f >>> 32))。
    5. 如果该域是double类型

      private double height;
      long heightBits=Double.doubleToLongBits(height);
      int heightTemp=(int)(heightBits ^ (heightBits >>> 32));
    6. 如果该域是一个对象引用,并且该类的equals方法通过递归调用equals的方式来比较这个域,则同样为这个域递归调用hashCode。

      private String name;
      int stringTemp=this.name.hashCode();

完整的Student类:

class Student{
    private String name;
    private int age;
    private double height;
    @Override
    public boolean equals(Object obj) {
        //使用==操作符检查“参数是否为这个对象的引用”
        if(this==obj)
            return true;
        //使用instanceof操作符检查“参数是否为正确的类型”
        if(!(obj instanceof Student))
            return false;
        //把参数转换成正确的类型。
        Student student=(Student) obj;
        //对于该类中的每个“关键”阈,检查参数中的阈是否与该对象中对应的阈相匹配。
        return  this.name==student.name && this.age==student.age && this.height==student.height;
    }

    @Override
    public int hashCode() {
        //初始化
        int result=17;
        //String类型
        result=this.name.hashCode()+result;
        //int类型
        result=this.age+result;
        //double类型
        long heightBits=Double.doubleToLongBits(height);
        int heightTemp=(int)(heightBits ^ (heightBits >>> 32));
        result=heightTemp+result;
        //返回
        return result;
    }
}
时间: 2024-10-11 12:00:08

如何正确的覆盖equals和hashCode的相关文章

Java提高篇——equals()与hashCode()方法详解

java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继承结构的基础,所以是每一个类的父类.所有的对象,包括数组,都实现了在Object类中定义的方法. equals()方法详解 equals()方法是用来判断其他的对象是否和该对象相等. equals()方法在object类中定义如下: public boolean equals(Object obj)

集合框架比较两个对象是否相同(equals和hashCode方法)

package com.dcz.hashset; import java.util.HashSet; import java.util.Set; /** * HashSet是接口最常用的实现类,顾名思义,底层采用了哈希表算法. * * 在HashSet中如何判断两个对象是否是否相等问题分析: * 1. 要用两个对象的equals方法比较,返回true说明对象相同. * 2. 两个对象的hashCode方法返回值相同. * * 对象hashCode决定了在哈希表中的存储位置. * * 向HashS

【Java实战】源码解析为什么覆盖equals方法时总要覆盖hashCode方法

1.背景知识 本文代码基于jdk1.8分析,<Java编程思想>中有如下描述: 另外再看下Object.java对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}. * <p> *

第9条:覆盖equals时总要覆盖hashCode

在每个覆盖equals方法的类中,也必须覆盖hashCode方法.否则,会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常工作,包括HashMap,HashSet,Hashtbale. hashCode约定内容: 1.只要对象equals方法的比较操作所用到的信息没有被修改,对同一对象调用多次,hashCode方法都必须返回同一整数.在同一应用程序的多次执行过程中,每次执行返回的整数可以不一致. 2.如果两个对象根据equals(Object)方法比较

Effective Item 6 - 覆盖equals方法时不要忘记hashCode方法

任何覆盖了equals方法的类都需要覆盖hashCode方法. 忽视这一条将导致类无法与基于散列的数据结构一起正常工作,比如和HashMap.HashSet和Hashtable. 下面是hashCode相关规范: ·在程序执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这个对象调用多少次hashCode,起结果必须始终如一地返回同一个证书. 如果是同一个程序执行多次,每次调用的结果可以不一致. ·如果两个对象根据equals方法比较是相等的,那么两个对象的hashCo

equals()和hashCode()必须同时覆盖的原因

我们再用JAVA创建自己的类的时候,一种比较常见的覆盖就是覆盖Object中的equals()方法和hashCode()方法.如果不这样做的话,就很可能违反Object.hashCode()的通用约定,从而在利用自己建的类构建需要Hash化的集合的正常工作.其中有一条约定很重要: 如果两个对象利用equals方法比较是相等的,那么这两个对象必须能返回同样的hashCode. 这一点很好理解,就比如拿Set来说,Set的特点就是元素是无须的且不可重复.那么这里面所谓的重复的定义,就是需要程序员通过

Effective Java - 注意覆盖equals

平时很难遇到需要覆盖equals的情况. 什么时候不需要覆盖equals? 类的每个实例本质上是唯一的,我们不需要用特殊的逻辑值来表述,Object提供的equals方法正好是正确的. 超类已经覆盖了equals,且从超类继承过来的行为对于子类也是合适的. 当确定该类的equals方法不会被调用时,比如类是私有的. 如果要问什么时候需要覆盖equals? 答案正好和之前的问题相反. 即,类需要一个自己特有的逻辑相等概念,而且超类提供的equals不满足自己的行为. (PS:对于枚举而言,逻辑相等

Java中==和equals的区别,equals和hashCode的区别

在java中: ==是运算符,用于比较两个变量是否相等. equals,是Objec类的方法,用于比较两个对象是否相等,默认Object类的equals方法是比较两个对象的地址,跟==的结果一样.Object的equals方法如下: public boolean equals(Object obj) { return (this == obj); } hashCode也是Object类的一个方法.返回一个离散的int型整数.在集合类操作中使用,为了提高查询速度.(HashMap,HashSet等

==、equals和hashCode小结

1.== ==是关系操作符,对于基本类型(byte,short,char,int,long,float,double,boolean),比较的是值是否相等:对于对象,比较的是对象的引用(也即栈内存中的存放地址)是否相等. 2.equals equals是Object类中的方法,默认比较引用,和==处理对象的结果一样,不适用于基本类型.Object中的equals方法如下: public boolean equals(Object obj){ return (this==obj); } 如果要用e