面试题答案
一键面试1. 重写方法说明
要在Set
集合中根据部分属性(如姓名和年龄)实现去重,需要重写自定义对象类的equals
和hashCode
方法。
equals
方法:用于定义两个对象在逻辑上相等的条件,在本题中,当两个对象的姓名和年龄都相等时,认为这两个对象相等。hashCode
方法:Set
集合通常基于哈希表实现,hashCode
方法返回对象的哈希码,用于快速定位对象在哈希表中的位置。如果两个对象通过equals
方法比较相等,那么它们的hashCode
方法必须返回相同的值。
2. 代码示例
import java.util.HashSet;
import java.util.Set;
class Person {
private String name;
private int age;
private String address;
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
@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 && name.equals(person.name);
}
@Override
public int hashCode() {
return 31 * name.hashCode() + age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
public class SetDuplicateRemovalExample {
public static void main(String[] args) {
Set<Person> personSet = new HashSet<>();
personSet.add(new Person("Alice", 30, "123 Wonderland"));
personSet.add(new Person("Bob", 25, "456 Elm St"));
personSet.add(new Person("Alice", 30, "789 Oak St"));
for (Person person : personSet) {
System.out.println(person);
}
}
}
在上述代码中:
Person
类定义了姓名、年龄和地址属性。- 重写了
equals
方法,当姓名和年龄相等时返回true
。 - 重写了
hashCode
方法,根据姓名和年龄计算哈希码。 - 在
main
方法中,创建了一个HashSet
并添加了一些Person
对象,最后遍历集合验证去重效果。
3. 多线程环境问题及解决方案
问题
- 线程安全问题:
HashSet
本身不是线程安全的,在多线程环境下,多个线程同时向HashSet
添加元素时,可能会导致数据不一致或ConcurrentModificationException
异常。例如,一个线程正在遍历集合,另一个线程同时修改集合结构,就会抛出该异常。 - 哈希冲突和去重准确性:在多线程环境下,由于不同线程计算哈希码和执行
equals
方法的时机不同,可能会出现哈希冲突,导致原本应该去重的对象没有被正确去重。
解决方案
- 使用线程安全的集合:可以使用
Collections.synchronizedSet
方法将HashSet
包装成线程安全的集合。例如:
Set<Person> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
- 使用并发集合:
ConcurrentHashMap
的newKeySet
方法可以创建一个线程安全的Set
,它使用分段锁机制来提高并发性能。例如:
Set<Person> concurrentSet = ConcurrentHashMap.newKeySet();
这样在多线程环境下,使用这些线程安全的集合就可以避免上述问题,确保去重操作的正确性和线程安全性。