黑马程序员_日记42_HashSet自定义对象去重练习

本文深入探讨了如何利用HashSet存储自定义对象,并通过重写hashCode和equals方法实现元素去重。通过实例演示了从创建Person类、存储到HashSet、到优化去重过程的完整流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 ——- android培训java培训、期待与您交流! ———-

往hashSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。

思路:
1 把数据存入Person,建立Person类
2 把Person对象存入HashSet,建立HashSet集
先运行一遍,观察运行结果,进行分析。

import java.util.*;
//1 把数据存入Person,建立Person类
class Person
{
    private String name;//姓名
    private int age;//年龄

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

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

    public String getName()
    {
        return name;
    }

    public void setAge(int age)
    {
        this.age =age;
    }

    public int getAge()
    {
        return age;
    }
}

//主类
class HashSetTest
{
    public static void main(String[] args)
    {
        //1 创建HashSet集
        HashSet hs = new HashSet();

        //2 把Person对象存入集合
        hs.add(new Person("Jack",20));
        hs.add(new Person("Jack",20));
        hs.add(new Person("Tom",18));
        hs.add(new Person("Tom",18));
        hs.add(new Person("Mike",19));
        hs.add(new Person("Jane",26));

        //3 取出元素
        for(Iterator it = hs.iterator(); it.hasNext(); )
        {
            //强制转换为Person
            Person p = (Person)it.next();
            System.out.println(p.getName()+"---"+p.getAge());
        }
    }
}

这里写图片描述
运行结果为:
Tom—18
Jack—20
Jane—26
Jack—20
Tom—18
Mike—19
观察发现,元素并没有去重,这是为什么呢??
这是因为HashSet调用了Object中的hashCode方法!
程序是这样工作的:
JVM调用hashCode方法计算了元素的地址值,
如果地址值不冲突,则存入HashSet。
而上面调用add方法时,每一个Person对象都是在内存新开辟一块空间,
地址值都是不一样的,不可能发生地址冲突,所以都成功的存入了HashSet。

所以,首先必须要做的事就是在Person类中覆盖Object的hashCode方法!
那么到底该怎么重写呢?
这里提供两种方式:
方式一:

public int hashCode()
{
    return 60;
}

方式二:

public int hashCode()
{
    return name.hashCode()+age*37;
}

需要解释的地方:
使用方式一,程序是这样走的:
每一个对象返回的哈希值都一样,发生了冲突,
那么它们就以链表的方式链接存储,
这样存入的元素越多,效率就越低,
为了减少比较次数,
就设计到了hashCode()的算法优化能力!
这里采用了简单的处理,如方式二。

使用方式二:
name是String类型的,String类已经覆盖了hashCode()方法,
所以,可以通过调用得到name的哈希值。
而age*37是为了减少哈希值相等的几率,
减少计算量,提高效率!
同时应该考虑到int的取值范围,应当用“+”求和,
而不是直接把name的哈希值乘以age。

接着上面的思路:
3 重写Person类中的hashCode方法
运行程序,观察结果。
发现仍然有重复的元素,这是为什么呢?
这是因为在判断元素的哈希值之后,
如果哈希值相同,会调用equals方法判断内容是否一样。
这就要求:
4 重写equals方法.

import java.util.*;
//1 把数据存入Person,建立Person类
class Person
{
    private String name;//姓名
    private int age;//年龄

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

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

    public String getName()
    {
        return name;
    }

    public void setAge(int age)
    {
        this.age =age;
    }

    public int getAge()
    {
        return age;
    }

    //重写hashCode方法
    public int hashCode()
    {
        return name.hashCode()+age*37;
    }

    //重写equals方法
    public boolean equals(Object obj)
    {
        //强制转换Person类型
        Person p = (Person)obj;

        //判断是否为同一个人
        return this.getName().equals(p.getName()) && this.getAge()==p.getAge();
    }
}

//主类
class HashSetTest
{
    public static void main(String[] args)
    {
        //1 创建HashSet集
        HashSet hs = new HashSet();

        //2 把Person对象存入集合
        hs.add(new Person("Jack",20));
        hs.add(new Person("Jack",20));
        hs.add(new Person("Tom",18));
        hs.add(new Person("Tom",18));
        hs.add(new Person("Mike",19));
        hs.add(new Person("Jane",26));

        //3 取出元素
        for(Iterator it = hs.iterator(); it.hasNext(); )
        {
            //强制转换为Person
            Person p = (Person)it.next();
            System.out.println(p.getName()+"---"+p.getAge());
        }
    }
}

这里写图片描述
运行结果:
Tom—18
Jane—26
Jack—20
Mike—19
说明已经成功去重了,HashSet中已经不存在同名同年龄的人了!

总结:在HashSet中,存入元素是先判断哈希值是否一样,再判断内容是否一样!
hashset为了保证元素唯一:
1 如果元素哈希值相同,就判断equals是否为true;
2 如果哈希值不相同,不会调用equals方法。
此外,contains()和remove()等操作,HashSet都是依赖hashCode()和equals方法。
所以在类中必须重写这两个方法,才能保证元素唯一!

### 如何使用 `HashSet` 除 Java 对象中的复项 在 Java 中,`HashSet` 实现了 `Set` 接口并提供了自动复元素的功能。由于 `HashSet` 底层依赖于 `HashMap` 来存储数据,在添加新元素时会依据该元素的哈希码决定其存放位置[^3]。 对于自定义对象而言,为了确保能够正确识别相同对象从而避免复,必须适当地写 `hashCode()` 和 `equals(Object obj)` 方法[^4]。这是因为 `HashSet` 判断两个对象是否相等的标准不仅限于它们具有相同的哈希码,还需要这两个对象通过 `equals()` 方法返回 true 才能认为是同一个对象[^5]。 下面是一个简单的例子展示如何创建一个不可变类,并为其提供合适的 `hashCode/equals` 实现以便可以在 `HashSet` 中正常工作: ```java import java.util.*; class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Person)) return false; Person person = (Person) o; // 如果name和age都一样则视为同一对象 return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } } public class Main { public static void main(String[] args) { List<Person> peopleWithDuplicates = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Alice", 30), // Duplicate entry new Person("Charlie", 28) ); Set<Person> uniquePeople = new HashSet<>(peopleWithDuplicates); System.out.println(uniquePeople.size()); // 输出应为3而不是4 } } ``` 在这个例子中,即使列表中有多个表示同一个人的不同实例(即拥有完全相同的属性),一旦这些实例被放入到 `HashSet` 后也只会保留一份副本。因此实现了的效果[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值