在 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()
方法返回true
,Set
会认为它们是相同的对象,从而去重。
4. 总结
-
Set<Integer>
可以正常去重,因为Integer
类已经正确重写了hashCode()
和equals()
方法。 -
自定义对象如果没有重写
hashCode()
和equals()
方法,Set
将无法正确去重。 -
为了让
Set
正确去重,自定义对象必须重写hashCode()
和equals()
方法,确保它们基于对象的内容而不是内存地址。