为什么 Object.equals(Object o) 在 java 中需要 Object.hashCode()?

Why does Object.equals(Object o) require Object.hashCode() in java?

我有一个 Person 类型的对象列表,我想使用流删除具有相同名称的元素。我在互联网上发现了使用 Wrapper class 的建议,到目前为止我的代码如下所示:

List<Person> people = Arrays.asList(new Person("Kowalski"),
                                    new Person("Nowak"),
                                    new Person("Big"),
                                    new Person("Kowalski"));

List<Person> distPeople = people.stream()
        .map(Wrapper::new)
        .distinct()
        .map(Wrapper::unwrap)
        .collect(Collectors.toList());

在文档中说 distinct()

Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.

Wrapper 的实现不起作用(我得到与两个 Kowalski 相同的流):

public class Wrapper
{
    private final Person person;

    Wrapper(Person p)
    {
        person = p;
    }

    public Person unwrap()
    {
        return person;
    }

    public boolean equals(Object other)
    {
        if(other instanceof Wrapper)
            return ((Wrapper) other).person.getName().equals(person.getName());
        else
            return false;
    }
}

Wrapper class 的实现在添加后有效:

@Override
public int hashCode()
{
    return person.getName().hashCode();
}

有人可以解释为什么在 Wrapper class distinct() 中覆盖 hashCode() 后有效吗?

来自等于 Java 文档

It is generally necessary to override the hashCode method whenever equals method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.

请阅读合同详情here

答案就在classDistinctOps中。方法 makeRef 用于 return 包含不同元素的 ReferencePipeline 实例。此方法利用 LinkedHashSet 执行 reduce 操作以获得不同的元素。请注意 LinkedHashSetHashSet 扩展而来,后者使用 HashMap 来存储元素。现在为了 HashMap 正常工作,您应该提供 hashCode() 的实现,它遵循 hashCode()equals() 之间的正确合同,因此,您需要提供hasCode() 的实现,以便 Stream#distinct() 正常工作。

distinct() 操作在内部使用 HashSet 来检查它是否已经处理了某个元素。 HashSet 又依赖于其元素 to sort them into buckets.

hashCode() 方法

如果您不重写 hashCode() 方法,它会回退到默认值,返回对象的标识,这通常在两个对象之间有所不同,即使根据 equal() 它们是相同的.因此 HashSet 将它们放入不同的桶中,并且无法再确定它们是 'same' 对象。