gpt4 book ai didi

java - Equals 和 hashCode 与 EqualsVerifier 的契约(Contract)

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:44:38 26 4
gpt4 key购买 nike

我对 Java 中使用 EqualsVerifierequalshashCode 契约有一些疑问图书馆。

假设我们有这样的东西

public abstract class Person {

protected String name;

@Override
public boolean equals(Object obj) {
// only name is taken into account
}

@Override
public int hashCode() {
// only name is taken into account
}

}

以及以下扩展类:

public final class Worker extends Person {

private String workDescription;

@Override
public final boolean equals(Object obj) {
// name and workDescription are taken into account
}

@Override
public final int hashCode() {
// name and workDescription are taken into account
}

}

我尝试使用 EqualsVerifier 来测试我是否实现了 Person 类中的 equalshashCode 契约。

    @Test
public void testEqualsAndHashCodeContract() {
EqualsVerifier.forClass(Person.class).verify();
}

运行此测试,我知道我必须声明 equalshashCode 方法为 final,但这是我不想做的事情,因为我可能想在扩展类中声明这两个方法,因为我想在 equalshashCode 中使用一些子属性。

您可以跳过测试 EqualsVerifier 库中的最终规则吗?还是我遗漏了什么?

最佳答案

免责声明:我是 EqualsVerifier 的创建者。我才刚刚发现这个问题:)。

Joachim Sauer 提到的解决方法是正确的。

让我解释一下为什么 EqualsVerifier 不喜欢您的实现。现在让我们假装 Person不是抽象的;它使示例更简单一些。假设我们有两个 Person对象,像这样:

Person person1 = new Person("John");
Person person2 = new Worker("John", "CEO of the world");

我们调用equals在这两个对象上:

boolean b1 = person1.equals(person2); // returns true
boolean b2 = person2.equals(person1); // returns false

b1是真的,因为 Personequals方法被调用,它忽略 workDescription . b2是错误的,因为 Workerequals方法被调用,instanceofgetClass()检查该方法返回 false。

换句话说,你的 equals方法不再对称,这是正确实现 equals 的要求, 根据 the Javadoc .

你确实可以使用 getClass()解决这个问题,但随后你遇到了另一个问题。假设您使用 Hibernate 或模拟框架。这些框架使用字节码操作来创建您的类的子类。本质上,您将获得这样的类(class):

class Person$Proxy extends Person { }

假设您像这样往返数据库:

Person person1 = new Person("John");
em.persist(person1);
// ...
Person fetchedPerson = em.find(Person.class, "John");

现在让我们调用equals :

boolean b3 = person1.equals(fetchedPerson); // returns false
boolean b4 = fetchedPerson.equals(person1); // also returns false

b3b4是假的,因为 person1fetchedPerson属于不同的类别(准确地说是 PersonPerson$Proxy)。 equals现在是对称的,所以至少它遵循契约(Contract),但它仍然不是你想要的:fetchedPerson不像Person那样“表现”了。用技术术语来说:这打破了 Liskov Substitution Principle ,这是面向对象编程的基础。

有一种方法可以完成所有这些工作,但它相当复杂。 (如果你真的想知道:this article 解释了如何。)为了简单起见,EqualsVerifier 建议你将你的 equalshashCode方法最终。在大多数情况下,这会很好地工作。如果你真的需要,你总是可以走复杂的路线。

在你的例子中,自 Person是抽象的,你也可以选择不实现 equalsPerson , 但仅限于 Worker (以及您可能拥有的任何其他子类)。

关于java - Equals 和 hashCode 与 EqualsVerifier 的契约(Contract),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19926486/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com