Java @Override equals(): 当 this.getClass() != o.getClass() 失败但不应该



我的MyClass类中有equals((的@Override:

@Entity( name = "MyClass" )
@Table( name = "my_class" )
public class MyClass extends MySuperClass
{
...
@Override
public boolean equals( Object o )
{
if ( this == o )
{
return true;
}
if ( o == null || this.getClass() != o.getClass() )
{
return false;
}
if ( !super.equals( o ) )
{
return false;
}
MyClass that = ( MyClass ) o;
return this.var1.equals( that.var1 ) && this.var2.equals( that.var2 );
}
...
}

相当标准。事实上,它遵循Java的最佳实践
在以后的生活中,我在另一个子包类(我的控制器类(中有这个:

...
package com.a.b.api.controllers;
...
import com.a.b.jpa.models.MyClass;
...
MyClass myObject1 = new MyClass( var1, var2 );
MyClass myObject2 = this.myClassRepository.getById( 1 ); // SpringBoot/Jpa/Hibernate
if ( myObject2.equals( myObject1 ) )
{
...do something...
}
...
this.myClassRepository.save( myObject1 );
...

我的问题是.equals((在这里总是失败:

if ( o == null || this.getClass() != o.getClass() )

因为java说this.getClass((o.getClass(。当我调试代码时(在Intellij IDEA 2022.1 UE中(,我看到的是:

this.getClass((=MyClass@13706

o.getClass=com.a.b.jpa.models.MyClass@8f7462

但它们同一类!几乎每一本Java书籍、教程、博客、Intellij IDEA等都以这种方式演示.equals((。我在Ubuntu 20.04.4 LTSjava-14-openjdk-amd64java-17-openjdk-amd64中尝试过,结果相同。

我做错了什么?

myObject2是一个代理类的实例,由Hibernate在运行时使用Byte Buddy生成。生成的代理截取所有方法调用,这就是getClass()返回不同结果的原因。

作为getClass()的替代方案,使用instanceof可能是另一种方法:

if ( !(this instanceof MyClass && o instanceof MyClass) )
{
return false;
}

但是请记住,instanceof也有其缺点。它违反了对称原则。

首先不应该比较这些对象,因为新对象应该与具有持久状态的Hibernate托管对象不同。

快乐歌曲 在他的回复中正确陈述:

myObject2是一个代理类的实例,由Hibernate在运行时使用Byte Buddy生成。生成的代理拦截所有方法调用,这就是getClass((返回不同结果的原因。

我真的不想使用instanceof,因为这被认为是不好的做法,所以我开始四处寻找,无意中发现了一篇有类似问题的帖子。他们的解决方案是将最终关键字添加到类声明中。我认为这微不足道,但尝试了一下——,它成功了添加最终关键字导致

if ( o == null || this.getClass() != o.getClass() )

if ( o == null || !this.getClass().equals( o.getClass() ) )

以正常工作。我的班级代码现在是:

@Entity( name = "MyClass" )
@Table( name = "my_class" )
final public class MyClass extends MySuperClass
{
...
@Override
public boolean equals( Object o )
{
if ( this == o )
{
return true;
}
if ( o == null || !this.getClass().equals( o.getClass() ) )
{
return false;
}
if ( !super.equals( o ) )
{
return false;
}
MyClass that = ( MyClass ) o;
return this.var1.equals( that.var1 ) && this.var2.equals( that.var2 );
}
...
}

感谢大家的帮助!非常感谢快乐歌曲为我指明了正确的方向!

我将此标准equalshashcode实现用于JPA实体(如本文所述(:

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof MyClass)) {
return false;
}
MyClass other = (MyClass) o;
return id != null && id.equals(other.getId());
}

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

您没有使用最佳实践。将您的平等待遇更改为如下内容(先进行空检查,然后进行相同检查,然后再进行类检查(:

public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != getClass()) {
return false;
}

... do the actual comparison here
}

注意:上面的代码是Apache EqualsBuilder 的转述

相关内容

最新更新