如何重写equals方法和hashCode方法

在实际应用中经常会比较两个对象是否相等,比如下面的Address类,它有两个属性:String province 和 String city。

public class Address {
    private String province;
    private String city;
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
   
    public Address() {}
    public Address(String province, String city) {this.province = province; this.city = city;}
   
}

在现实生活中我们认为若两个 Address 的 province 和 city 属性相同,则它们应该是同一个地址(省市都一样,当然就是同一个地区啦)。但下面的代码却表明:address1 和 address2 是两个“不同的地址”

public class TestAddress {
   
    public static void main(String[] args) {
        Address address1 = new Address("广东","广州");
        Address address2 = new Address("广东", "广州");
       
        System.out.println(address1 == address2);//false
        System.out.println(address1.equals(address2));//false
        System.out.println(address1.hashCode() == address2.hashCode());//false
    }
}

其原因是:在Java(编程语言)中比较对象 和 现实生活中 比较两个对象是两个不同的概念,前者暂且称为“物理相等”,而后者是“逻辑相等”。

adress1==adress2 是根据两个对象的内存地址是否相同进行比较的,第4、5行分别 new 了两个对象,这两个对象存储在内存中不同的地址,当然不会相等了。

由于Address类并没有重写equals方法,那么address1.equals(address2) 执行的就是Object类的equals方法,而java.lang.Object类的equlas方法是这样实现的:

public boolean equals(Object obj) { return (this == obj); }

JDK中对该方法的注释如下:也就是说:Object类的equals方法 是通过 == 来比较两个对象是否相等的,也即根据 对象x引用 和 对象y 的引用是否指向内存中的同一个地址 来判断 对象x 和 对象y 是否相等。

* 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}).

而按照现实思维,既然 adress1 和 address2 都代表广东广州,那么在程序中它们两个对象比较就应该相等(逻辑上相等),也即address1.equals(address2)应该返回true才对。于是就需要覆盖 Object 类中的 equals 方法 和 hashCode方法了。

而覆盖 equals方法 和hashCode方法是需要技巧的。

①覆盖了Object类的equals方法后,需要再覆盖 Object类的hashCode方法。为什么呢?----不要违反“hashCode方法的 通过约定(general contract) ”

Object类的equals方法上的注释如下:

/ * 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. */ public boolean equals(Object obj) { return (this == obj); } 

而这个“通用约定”就是:❶若两个对象根据equals(Object)方法比较相等,那么调用这两个对象中任意一个对象的hashCode方法 都必须 产生同样的整数结果。

❷若两个对象根据equals(Object)方法比较相等,那么调用这两个对象中任意一个对象的hashCode方法 可以 产生相同的整数结果,但是最好 产生不同的整数结果,这样可以提供散列表的性能(当要把Address类 作为 键 put 到HashMap中时,可以减少冲突,可参考这篇文章

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b28f100fa276ca9694376603a67f7554.html