java基础之equals方法和hashcode方法

引言

java基础系列之前已经剖析过好几个java里面比较关键的关键字了,今天我们来讲讲容易被人忽视的equals方法和hashcode方法。为什么说容易被人忽视,因为这两货就算你理他,也不会出什么问题,java的上帝类Object自带equals方法和hashcode方法,所以不用你操心,然鹅只要你根据业务需求来重写equals方法,就很有可能出错,今天我们就来看看这两个方法。

equals方法

每个对象默认都是用上帝类Object的equals方法:

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

非常简单粗暴的直接判断是否为当前对象,如果不是直接返回false。如果你自定义的对象要判断两个对象是否相等直接用父类的equals方法是不行的,做个试验:

public class TestEquals {

    private String testName;
    private Integer age;
    
    //省略 getter setter方法
}

    TestEquals test1 = new TestEquals();
    test1.setTestName("test");
    test1.setAge(10);
    TestEquals test2 = new TestEquals();
    test2.setTestName("test");
    test1.setAge(10);
    System.out.println(test1.equals(test2));

上面100%返回false,因为是两个对象,但是在业务上很可能是需要返回true的,因为数据都一样需要它是equal的。所以在实际开发场景下重写equals方法的概率还是很大的。

在重写equals方法时我们需要注意遵守以下条件:

  • 自反性:x.equals(x)必须返回true。
  • 对称性:x.equals(y)与y.equals(x)的返回值必须相等。
  • 传递性:x.equals(y)为true,y.equals(z)也为true,那么x.equals(z)必须为true。
  • 一致性:如果对象x和y在equals()中使用的信息都没有改变,那么x.equals(y)值始终不变。
  • 对于任何非空引用值x,x.equal(null)应返回false。

重写equals方法最佳实践可以按照以下步骤来做:

  1. 使用==操作符判断是否当前对象(判断参数是否为该对象的引用),如果是直接返回true。
  2. 使用instanceof判断是否为目标类的实例如果不是直接返回false。
  3. 根据你的业务逻辑使用Objects.equals方法判断各个字段是否相同。
  4. 重写equals方法后必须重写hashcode方法。

hashcode方法

hashcode方法很多初学者一开始都很迷惑这个方法有什么用,当你看了java的集合之后应该会找到答案。对hashcode在集合类里面是有作用的特别是底层数据结构是hash表的集合类如HashMap、HashSet等。

以HashMap为例,在往HashMap中存Element时,首先会先调用key的hashcode方法,并且进一步根据HashMap的hash方法进行再哈希,进而找到需要存放的地址。并且HashMap的元素是不重复的,如果重复插入相同的对象是value是会被覆盖的。HashMap的get方法也是一样先要通过hash方法找到Element在哈希表上位置。上面说到重写了equals方法必须重写hashcode方法是因为如果只重写equals方法会打破元素不重复的规则,重复插入相同的key并不会在哈希表上找到同一个位置,原因是hashcode不一致,最后将会导致相同的几个元素在哈希表上的多个位置上出现。如果你equals方法都不重写估计你put进HashMap的元素再get出来很可能返回NULL。有兴趣的同学可以自己去试验下。多说一句,有的人说为啥我如果key是String类型就没问题,那是因为String的equals方法和hashcode方法已经被重写过了。

hashcode方法重写的最佳实践

  • 定义一个种子数。
  • 用该种子数*31+你的字段的hashcode赋值
    例如:
public int hashcode() {
    int hash = 17;
    hash = hash*31+field1.hashcode();
    hash = hash*31+filed2.hashcode();
    ........
}

或者你也可以使用Objects.hashcode方法,把你要比较的fields当做参数传进去就可以了。

猜你喜欢

转载自blog.csdn.net/nethackatschool/article/details/87990336