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

时间:2018-06-26 18:27:20

标签: java java-8 java-stream distinct hashcode

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

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()

  

返回由不同元素组成的流(根据   该流的Object.equals(Object))。

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类的实现将生效:

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

有人可以解释为什么在hashCode()Wrapper中重写distinct()后起作用了吗?

3 个答案:

答案 0 :(得分:2)

从等于Java文档开始

  

通常每当有必要重写hashCode方法时,   等于方法被重写,从而维护总合同   对于hashCode方法,该方法指出相等的对象必须具有   相等的哈希码。

请阅读有关合同here的详细信息

答案 1 :(得分:2)

答案在List类中。方法DistinctOps用于返回包含不同元素的makeRef实例。此方法利用ReferencePipeline执行LinkedHashSet操作以获取不同的元素。请注意,reduce是从LinkedHashSet扩展而来的,其中HashSet使用HashMap存储元素。现在,为了使HashMap正常工作,您应该提供hashCode()的实现,该实现遵循hashCode()equals()之间的正确约定,因此,需要提供hasCode()的实现,以便Stream#distinct()正常工作。

答案 2 :(得分:2)

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

如果不重写hashCode()方法,它将退回到其默认值,并返回对象的身份,这通常在两个对象之间有所不同,即使根据equal()它们是相同的。因此HashSet将它们放入不同的存储桶中,无法再确定它们是“相同”对象。