欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

向HashSet中添加自定义对象如何区别添加的对象

程序员文章站 2024-02-27 23:47:21
...

一、问题来源

当向HashSet中添加String类型的数据时,如果同时添加两个相同的字符串,那么实际上只能添加一个,因为HashSet不允许添加相同的元素.


二、问题分析

问题来了,HashSet是如何区别两个对象(String类型的数据是引用数据类型)的?

浅显的说,String重写了Object类的equals方法和hashCode方法.因此,在比较的时候,HashSet调用了String类中重写的equals方法和hashCode方法.因此会按照String类中定义的判断方式来比较对象是否相同.

判断两个对象是否相等的方式

  1. 首先两个对象的hashCode是否相等,假如相等的话,那么就认为两个对象相等
  2. 假如两个对象的hashCode值不等,那么就通过equals方法来判断两个对象是否相等.默认的equals方法是比较两个对象指向的对象在内存中存储的地址的值是否相等.

现在需求 : 需要利用对象里面的值来判断是否相等

  1. 首先需要重写hashCode方法.(必须重写hashCode方法!)
  2. 其次需要重写equals方法.

假如只重写equals方法会出现什么情况呢?
只重写equals方法,那么重写的equals方法是无效的!
原因是添加对象时首先会调用父类Object类中的hashCode方法(本地方法,无法根据散列码得到对象的内存地址,但实际上,hashcode是根据对象的内存地址经哈希算法得来的).因此两个对象的hashCode的值是不相等的!这样就会认为这是两个不同的元素.


三、代码演示

了解了这些东西,下面开始自己定义一个类,来添加自定义的类

Student类(未重写equals和hashCode方法)

package cn.com.clearlight.setframe.set.bean;

import java.util.Objects;

public class Student implements Comparable<Student>{
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

HashSet实体类

package cn.com.clearlight.setframe.set;

import cn.com.clearlight.setframe.set.bean.Student;

import java.util.HashSet;

public class HashSetForEquals {
    public static void main(String[] args) {
        HashSet<Student> hs = new HashSet<>();

        hs.add(new Student("a", 1));
        hs.add(new Student("a", 1));
        hs.add(new Student("ab", 1));

        for (Student s :
                hs) {
            System.out.println(s.getName() + " : " + s.getAge());
        }
    }
}
	

输出结果:

ab : 1
a : 1
a : 1

相同元素仍然被添加进去,原因是没有在Student类中自定义自己想要比较的equals方法,因此调用父类Object中的equals方法.比较的是两个对象的引用地址是否相同,new出两个对象,所以地址肯定不相同,因此可以添加两个看上去一样的对象!

重写hashCode方法

public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

重写equals方法

	@Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Student other = (Student) obj;
        if (age != other.age) {
            return false;
        }
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        return true;
    }

首先比较两个对象是否指向同一个内存地址.之后在使用自己自定义方法通过年龄,姓名是否相同来确定两个是否相等.

此时运行实体类结果为:

a : 1
ab : 1


四、总结

通过向HashSet中添加自定义对象的实例,我们知道必须要在自定义的类中重写hashCode和equals方法! 重写之后,我们就可以根据我们的需求来添加元素.


[参考文章]

  1. 为什么重写equals一定要重写hashcode?
  2. 详解重写equals()方法就必须重写hashCode()方法的原因