- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我对 Java 中使用 EqualsVerifier 的 equals
和 hashCode
契约有一些疑问图书馆。
假设我们有这样的东西
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 类中的 equals
和 hashCode
契约。
@Test
public void testEqualsAndHashCodeContract() {
EqualsVerifier.forClass(Person.class).verify();
}
运行此测试,我知道我必须声明 equals
和 hashCode
方法为 final,但这是我不想做的事情,因为我可能想在扩展类中声明这两个方法,因为我想在 equals
和 hashCode
中使用一些子属性。
您可以跳过测试 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
是真的,因为 Person
的 equals
方法被调用,它忽略 workDescription
. b2
是错误的,因为 Worker
的 equals
方法被调用,instanceof
或 getClass()
检查该方法返回 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
b3
和 b4
是假的,因为 person1
和 fetchedPerson
属于不同的类别(准确地说是 Person
和 Person$Proxy
)。 equals
现在是对称的,所以至少它遵循契约(Contract),但它仍然不是你想要的:fetchedPerson
不像Person
那样“表现”了。用技术术语来说:这打破了 Liskov Substitution Principle ,这是面向对象编程的基础。
有一种方法可以完成所有这些工作,但它相当复杂。 (如果你真的想知道:this article 解释了如何。)为了简单起见,EqualsVerifier 建议你将你的 equals
和 hashCode
方法最终。在大多数情况下,这会很好地工作。如果你真的需要,你总是可以走复杂的路线。
在你的例子中,自 Person
是抽象的,你也可以选择不实现 equals
在Person
, 但仅限于 Worker
(以及您可能拥有的任何其他子类)。
关于java - Equals 和 hashCode 与 EqualsVerifier 的契约(Contract),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19926486/
我一直在使用 spock 编写测试。但是为了测试 Equals Hashcode 合约,我尝试使用 EqualsVerifier .所以我的测试代码看起来像: def "test equals has
设置,java 8 使用 lombok、meanbean 和 equalsverifier(所有 3 个的忠实粉丝,并且根据公司政策我可以使用的版本也有限制 - 在 equalsverifier 的
我对 Java 中使用 EqualsVerifier 的 equals 和 hashCode 契约有一些疑问图书馆。 假设我们有这样的东西 public abstract class Person {
我是一名优秀的程序员,十分优秀!