MST

星途 面试题库

面试题:自定义对象在Java Set集合去重中的复杂应用

假设有一个复杂的自定义对象类,它包含多个属性(如姓名、年龄、地址等),要求在一个Set集合中根据部分属性(如姓名和年龄)实现去重。请详细说明需要重写哪些方法来确保正确去重,并且通过代码实现一个完整的示例,包括自定义对象类、添加对象到Set集合以及验证去重效果的过程。同时,分析在多线程环境下,使用这种Set集合去重可能出现的问题及解决方案。
45.5万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. 重写方法说明

要在Set集合中根据部分属性(如姓名和年龄)实现去重,需要重写自定义对象类的equalshashCode方法。

  • 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<>());
  • 使用并发集合ConcurrentHashMapnewKeySet方法可以创建一个线程安全的Set,它使用分段锁机制来提高并发性能。例如:
Set<Person> concurrentSet = ConcurrentHashMap.newKeySet();

这样在多线程环境下,使用这些线程安全的集合就可以避免上述问题,确保去重操作的正确性和线程安全性。