Java中什么情况下需要重写hashCode()和equals()

重写hashCode()与equals()的必要性

只有在使用HashMap、HashSet等数据结构时,并且存储的对象是我们自定义的对象时,才需要重写。

基本类型的包装类以及String已经有了默认实现。

例如Integer类

    public static int hashCode(int value) {
        return value;
    }

以及String类

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

上述内置的类在使用过程中都不需要做处理,下面再看看我们自定义的类。

定义一个类Student

class Student{
    /**姓名**/
    private String name;

    /**性别**/
    private Integer gender;

    /**密码**/
    private String pwd;

    public Student(String name, Integer gender, String pwd) {
        this.name = name;
        this.gender = gender;
        this.pwd = pwd;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

new三个相同属性的对象,获取hashCode

public class Test {

    public static void main(String[] args) {
        Student student1 = new Student("a", 1, "pwd");
        Student student2 = new Student("a", 1, "pwd");
        Student student3 = new Student("a", 1, "pwd");
        System.out.println(student1.hashCode());
        System.out.println(student2.hashCode());
        System.out.println(student3.hashCode());

        HashSet<Student>set = new HashSet<>();
        set.add(student1);
        System.out.println(set.contains(student2));
    }
}

hasCode各不相同

460141958
1163157884
1956725890
false

假如在现有场景下,name是唯一主键,只要name相同,就默认Student相同。

所以在Student类中重写hashCode()

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

得到结果

128
128
128
false

hashCode相同了,但是得到的结果还是false。这是因为没有重写equals()方法,即使三个对象的hashCode()相同,也会被当成hash冲突来处理,这三个对象依然是不等价的。

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return name.equals(student.name);
    }

重写equals()后,这三个对象才算是等价的。

128
128
128
true

自定义对象默认的hashCode

自定义对象hashCode是根据对象的地址计算得出的。

去掉Student中重写的hashCode(),重新测试下

public class Test {

    public static void main(String[] args) {
        Student student1 = new Student("a", 1, "pwd");
        Student student2 = new Student("a", 1, "pwd");
        Student student3 = new Student("a", 1, "pwd");
        System.out.println(student1.hashCode());
        System.out.println(student2.hashCode());
        System.out.println(student3.hashCode());

        System.out.println(student1);
        System.out.println(student2);
        System.out.println(student3);
    }
}

得到的结果:

460141958
1163157884
1956725890
com.dayrain.demo12.Student@1b6d3586
com.dayrain.demo12.Student@4554617c
com.dayrain.demo12.Student@74a14482

现在删除中间的student2

public class Test {

    public static void main(String[] args) {
        Student student1 = new Student("a", 1, "pwd");
        Student student3 = new Student("a", 1, "pwd");
        System.out.println(student1.hashCode());
        System.out.println(student3.hashCode());

        System.out.println(student1);
        System.out.println(student3);
    }
}

得到的结果:

460141958
1163157884
com.dayrain.demo12.Student@1b6d3586
com.dayrain.demo12.Student@4554617c

Java按照顺序给对象分配内存,与我们所定义的对象名称无关。

并且hashCode是通过对象的地址计算的,而非对象名。

(上述的实验并不能得出相关结论,经过后续的资料查找,发现hashCode有多种实现方式,可以通过-XX:hashCode = 指定)

默认情况下是-XX:hashCode = 5,是一个与当前线程有关的随机数与其他三个固定值进行xorshift运算后的结果数。

具体可参考

JDK核心JAVA源码解析(9) - hashcode 方法_张哈希的博客-CSDN博客

How does the default hashCode() work?

关于Java中HashCode的一些思考_DotWait的博客-CSDN博客

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值