我的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-amd64和java-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 );
}
...
}
感谢大家的帮助!非常感谢快乐歌曲为我指明了正确的方向!
我将此标准equals
和hashcode
实现用于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 的转述