ps:作者是正在学习Java的小白,文章内容主要借鉴于JavaGuide,并且根据自己需要进行了一些改动,便于以后coding使用,原文地址:https://github.com/Uplpw/JavaGuide/blob/master/docs/java/basis/Java基础知识.md

hashCode是什么?

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。

hashCode()定义在 JDK 的 Object 类中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。

equal()是什么?

equals() 作用不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。equals()方法存在于Object类中,而Object类是所有类的直接或间接父类。

equals() 方法存在两种使用情况:

  • 类没有覆盖 equals()方法 :通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象,使用的默认是 Objectequals()方法。
  • 类覆盖了 equals()方法 :一般我们都覆盖 equals()方法来比较两个对象中的属性是否相等;若它们的属性相等,则返回 true(即,认为这两个对象相等)。

hashCode() 和 equals()的关系

一般来说,hashCode()equals()的关系分2种情况。

第一种情况

本质不是是散列表的数据结构(散列表是指如HashSet, Hashtable, HashMap的数据结构),此时hashCode()equals()就没有关系。
这种情况下,为了比较两个对象是否相等,只需要重写equals()

参考代码如下:

class Animal {
    private String type;
    private int age;

    public Animal(String type, int age) {
        this.type = type;
        this.age = age;
    }

    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }

        if (this == obj) {
            return true;
        }

        if (this.getClass() != obj.getClass()) {
            return false;
        }

        Animal animal = (Animal) obj;
        return this.type.equals(animal.type) && this.age == animal.age;
    }

    public String toString() {
        return "(" + this.type + ", " + this.age + ")";
    }
}

public class HashCodeAndEqual {
    public static void main(String[] args) {
        Animal animal1 = new Animal("dog", 1);
        Animal animal2 = new Animal("dog", 1);
        Animal animal3 = new Animal("cat", 1);

        System.out.println("animal1.equals(animal2): " + animal1.equals(animal2));
        System.out.println("animal1.hashCode(): " + animal1.hashCode() + ", animal2.hashCode(): " + animal2.hashCode());

        System.out.println("animal1.equals(animal3): " + animal1.equals(animal3));
        System.out.println("animal1.hashCode(): " + animal1.hashCode() + ", animal3.hashCode(): " + animal3.hashCode());
    }
}

结果如下:

animal1.equals(animal2): true
animal1.hashCode(): 713338599, animal2.hashCode(): 168423058
animal1.equals(animal3): false
animal1.hashCode(): 713338599, animal3.hashCode(): 821270929

结果分析:
equals()相等情况下,hashCode()不一定相等,所以本质不是是散列表的数据结构,此时hashCode()equals()是没有关系的。

第二种情况

本质是是散列表的数据结构,此时hashCode()equals()是有关系的。
这种情况下,为了比较两个对象是否相等,不仅要重写equals()还要重写hashCode()

参考代码如下:

class Plant {
    private final String type;
    private final int age;

    public Plant(String type, int age) {
        this.type = type;
        this.age = age;
    }

//    @Override
//    public int hashCode(){
//        int typeHash =  this.type.toLowerCase().hashCode();
//        return typeHash * age;
//    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }

        if (this == obj) {
            return true;
        }

        if (this.getClass() != obj.getClass()) {
            return false;
        }

        Plant animal = (Plant) obj;
        return this.type.equals(animal.type) && this.age == animal.age;
    }

    public String toString() {
        return "(" + this.type + ", " + this.age + ")";
    }
}
public class HashCodeAndEqual {
    public static void main(String[] args) {
        Plant plant1 = new Plant("tree", 10);
        Plant plant2 = new Plant("tree", 10);
        Plant plant3 = new Plant("flower", 1);
        Plant plant4 = new Plant("Tree", 10);

        HashSet<Plant> plantSet = new HashSet<>();
        plantSet.add(plant1);
        plantSet.add(plant2);
        plantSet.add(plant3);
        plantSet.add(plant4);

        System.out.println("plant1.equals(plant2): " + plant1.equals(plant2));
        System.out.println("plant1.hashCode(): " + plant1.hashCode() + ", plant2.hashCode(): " + plant2.hashCode());

        System.out.println("plant1.equals(plant3): " + plant1.equals(plant3));
        System.out.println("plant1.hashCode(): " + plant1.hashCode() + ", plant3.hashCode(): " + plant3.hashCode());

        System.out.println("plant1.equals(plant4): " + plant1.equals(plant4));
        System.out.println("plant1.hashCode(): " + plant1.hashCode() + ", plant4.hashCode(): " + plant4.hashCode());

        System.out.println(plantSet);
    }
}

结果如下:

// 注释掉重写的hashCode()
plant1.equals(plant2): true
plant1.hashCode(): 1160460865, plant2.hashCode(): 1247233941
plant1.equals(plant3): false
plant1.hashCode(): 1160460865, plant3.hashCode(): 258952499
plant1.equals(plant4): false
plant1.hashCode(): 1160460865, plant4.hashCode(): 603742814
[(tree, 10), (Tree, 10), (tree, 10), (flower, 1)]

// 加上重写的hashCode()
plant1.equals(plant2): true
plant1.hashCode(): 35685420, plant2.hashCode(): 35685420
plant1.equals(plant3): false
plant1.hashCode(): 35685420, plant3.hashCode(): -1271629221
plant1.equals(plant4): false
plant1.hashCode(): 35685420, plant4.hashCode(): 35685420
[(tree, 10), (Tree, 10), (flower, 1)]

结果分析:
(1)注释掉重写的hashCode()
重写了equals()。但是,HashSet中仍然有重复元素,why?这是因为虽然plant1 和 plant2的内容相等,但是它们的hashCode()不等;所以,HashSet在添加plant1 和 plant2的时候,认为它们不相等。
(2)加上重写的hashCode()
此时重写的equals()生效了,HashSet中没有重复元素。同时也发现,即使是hashCode()相等而equals()不相等。

总结
综上,使用散列表判断两个对象是否相等时,优先使用hashCode()来判断,如果不等,则直接判断两个对象不等,如果相等再使用equals()判断两个对象是否相等。

最后建议,重写equals()时最好重写hashCode(),这样不管是什么本质的数据结构都不会出现问题。

参考
https://www.cnblogs.com/skywang12345/p/3324958.html

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐