为什么自定义对象无法用set去重的解释

在 Java 中,Set 的去重机制依赖于对象的 hashCode() 和 equals() 方法。如果两个对象的 hashCode() 返回值相同,并且 equals() 方法返回 true,则 Set 会认为这两个对象是相同的,从而去重。

对于 Integer 类型,hashCode() 和 equals() 方法已经被正确重写,因此 Set<Integer> 可以正常去重。而对于自定义对象,如果没有正确重写 hashCode() 和 equals() 方法,Set 就无法正确去重。


1. Set<Integer> 的去重示例

Integer 类已经正确重写了 hashCode() 和 equals() 方法,因此 Set<Integer> 可以正常去重。

import java.util.HashSet;
import java.util.Set;

public class IntegerSetExample {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(1); // 重复元素,不会被添加

        System.out.println(set); // 输出: [1, 2]
    }
}

2. 自定义对象未重写 hashCode() 和 equals() 的示例

如果自定义对象没有重写 hashCode() 和 equals() 方法,Set 将无法正确去重。

(1) 自定义对象
class Person {
    private String name;
    private int age;

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

    // 未重写 hashCode() 和 equals() 方法

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}
(2) 测试代码
import java.util.HashSet;
import java.util.Set;

public class PersonSetExample {
    public static void main(String[] args) {
        Set<Person> set = new HashSet<>();
        set.add(new Person("Alice", 20));
        set.add(new Person("Bob", 25));
        set.add(new Person("Alice", 20)); // 重复对象,但会被添加

        System.out.println(set);
        // 输出: [Person{name='Alice', age=20}, Person{name='Bob', age=25}, Person{name='Alice', age=20}]
    }
}

原因分析

  • 由于 Person 类没有重写 hashCode() 和 equals() 方法,Set 会使用默认的 Object 类的实现。

  • 默认的 hashCode() 方法基于对象的内存地址,因此两个 Person 对象的哈希值不同。

  • 默认的 equals() 方法比较的是对象的内存地址,因此两个 Person 对象即使内容相同,也会被认为是不同的对象。


3. 重写 hashCode() 和 equals() 的示例

为了让 Set 正确去重,我们需要在 Person 类中重写 hashCode() 和 equals() 方法。

(1) 重写 hashCode() 和 equals()
import java.util.Objects;

class Person {
    private String name;
    private 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 == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

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

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}
(2) 测试代码
import java.util.HashSet;
import java.util.Set;

public class PersonSetExample {
    public static void main(String[] args) {
        Set<Person> set = new HashSet<>();
        set.add(new Person("Alice", 20));
        set.add(new Person("Bob", 25));
        set.add(new Person("Alice", 20)); // 重复对象,不会被添加

        System.out.println(set);
        // 输出: [Person{name='Alice', age=20}, Person{name='Bob', age=25}]
    }
}

原因分析

  • 重写 hashCode() 和 equals() 后,Set 会根据对象的内容来判断是否重复。

  • 两个 Person 对象的 name 和 age 相同,因此它们的 hashCode() 返回值相同,且 equals() 方法返回 trueSet 会认为它们是相同的对象,从而去重。


4. 总结

  • Set<Integer> 可以正常去重,因为 Integer 类已经正确重写了 hashCode() 和 equals() 方法。

  • 自定义对象如果没有重写 hashCode() 和 equals() 方法,Set 将无法正确去重。

  • 为了让 Set 正确去重,自定义对象必须重写 hashCode() 和 equals() 方法,确保它们基于对象的内容而不是内存地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值