为什么 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
操作以获得不同的元素。请注意 LinkedHashSet
从 HashSet
扩展而来,后者使用 HashMap
来存储元素。现在为了 HashMap
正常工作,您应该提供 hashCode()
的实现,它遵循 hashCode()
和 equals()
之间的正确合同,因此,您需要提供hasCode()
的实现,以便 Stream#distinct()
正常工作。
distinct()
操作在内部使用 HashSet
来检查它是否已经处理了某个元素。 HashSet
又依赖于其元素 to sort them into buckets.
的 hashCode()
方法
如果您不重写 hashCode()
方法,它会回退到默认值,返回对象的标识,这通常在两个对象之间有所不同,即使根据 equal()
它们是相同的.因此 HashSet
将它们放入不同的桶中,并且无法再确定它们是 'same' 对象。
我有一个 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
操作以获得不同的元素。请注意 LinkedHashSet
从 HashSet
扩展而来,后者使用 HashMap
来存储元素。现在为了 HashMap
正常工作,您应该提供 hashCode()
的实现,它遵循 hashCode()
和 equals()
之间的正确合同,因此,您需要提供hasCode()
的实现,以便 Stream#distinct()
正常工作。
distinct()
操作在内部使用 HashSet
来检查它是否已经处理了某个元素。 HashSet
又依赖于其元素 to sort them into buckets.
hashCode()
方法
如果您不重写 hashCode()
方法,它会回退到默认值,返回对象的标识,这通常在两个对象之间有所不同,即使根据 equal()
它们是相同的.因此 HashSet
将它们放入不同的桶中,并且无法再确定它们是 'same' 对象。