Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Equals与EqualsVerifier的hashCode契约_Java_Equals_Hashcode_Final_Equalsverifier - Fatal编程技术网

Java Equals与EqualsVerifier的hashCode契约

Java Equals与EqualsVerifier的hashCode契约,java,equals,hashcode,final,equalsverifier,Java,Equals,Hashcode,Final,Equalsverifier,我对Java中使用库的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()

我对Java中使用库的
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
    }

}
我尝试使用

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


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

正确处理这一点非常棘手

解释一种变通方法:

EqualsVerifier.forClass(MyClass.class)
    .withRedefinedSubclass(SomeSubclass.class)
    .verify();

请注意,要使其起作用,您可能需要在equals中选中
getClass()
,因为
工作者可以(或应该)永远不等于
免责声明:我是equalVerifier的创建者。我才发现这个问题:)

Joachim Sauer提到的变通方法是正确的

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

Person person1 = new Person("John");
Person person2 = new Worker("John", "CEO of the world");
class Person$Proxy extends Person { }
Person person1 = new Person("John");
em.persist(person1);
// ...
Person fetchedPerson = em.find(Person.class, "John");
让我们对这两个对象调用
equals

boolean b1 = person1.equals(person2); // returns true
boolean b2 = person2.equals(person1); // returns false
b1
为true,因为调用了
Person
equals
方法,它忽略了
工作描述
b2
为false,因为调用了
Worker
equals
方法,并且该方法中的
instanceof
getClass()
检入返回false

换句话说,您的
equals
方法不再是对称的,这是正确实现
equals
的必要条件,根据

您确实可以使用
getClass()
来绕过这个问题,但随后会遇到另一个问题。假设您使用Hibernate或模拟框架。这些框架使用字节码操作来创建类的子类。基本上,您将得到如下类:

Person person1 = new Person("John");
Person person2 = new Worker("John", "CEO of the world");
class Person$Proxy extends Person { }
Person person1 = new Person("John");
em.persist(person1);
// ...
Person fetchedPerson = em.find(Person.class, "John");
假设您往返访问数据库,如下所示:

Person person1 = new Person("John");
Person person2 = new Worker("John", "CEO of the world");
class Person$Proxy extends Person { }
Person person1 = new Person("John");
em.persist(person1);
// ...
Person fetchedPerson = em.find(Person.class, "John");
现在让我们调用
等于

boolean b3 = person1.equals(fetchedPerson); // returns false
boolean b4 = fetchedPerson.equals(person1); // also returns false
b3
b4
为假,因为
person1
fetchedPerson
属于不同的类别(
Person
Person$Proxy
equals
现在是对称的,所以至少它遵循契约,但它仍然不是您想要的:
fetchedPerson
不再像
人那样“行为”。在技术方面:这打破了面向对象编程的基础

有一种方法可以完成所有这些工作,但它相当复杂。(如果你真的想知道:解释怎么做。)为了保持简单,EqualsVerifier建议你将
方法设为equals
hashCode
方法为final。在大多数情况下,这将很好地工作。如果你真的需要,你可以走复杂的路线


在您的情况下,由于
Person
是抽象的,您也可以选择不在
Person
中实现
equals
,而只在
Worker
(以及您可能拥有的任何其他子类)中实现!非常感谢你!下一次,我会尽量不等到一年后再回复:)。