我有一些带有@Transient
注解的JPA实体属性。
在equals/hashCode/toString
方法中,我应该使用这些属性吗?
我的第一反应是不应该用,但我不知道原因。
- 有什么提示吗?
- 有什么想法吗?
- 有什么解释吗?
toString()
的情况不同,你可以随心所欲地使用 toString()
,因此我只会涵盖 equals()
(和 hashCode()
)。List
、Map
或 Set
中存储一个对象,则有一个要求,即必须实现 equals
和 hashCode
,以便它们遵守文档中指定的标准契约。equals()
和 hashCode()
?一个“自然”的想法是将映射为 Id
的属性作为 equals()
的一部分。public class User {
...
public boolean equals(Object other) {
if (this==other) return true;
if (id==null) return false;
if ( !(other instanceof User) ) return false;
final User that = (User) other;
return this.id.equals( that.getId() );
}
public int hashCode() {
return id==null ? System.identityHashCode(this) : id.hashCode();
}
}
Set
中,则其哈希码将在Set
中的时间内发生变化,这会违反Set
的契约。public class User {
...
public boolean equals(Object other) {
if (this==other) return true;
if ( !(other instanceof User) ) return false;
final User that = (User) other;
return this.username.equals( that.getUsername() );
}
public int hashCode() {
return username.hashCode();
}
}
Set
中,则更改hashcode
会破坏Set
的契约。业务键的属性不必像数据库主键那样稳定,您只需要保证对象在同一Set
中时具有稳定性。——12.1.3. Considering object identity
建议使用业务键相等性来实现equals()
和hashCode()
。业务键相等性意味着equals()
方法仅比较形成业务键的属性。它是在现实世界中标识我们实例的关键(自然候选键)。——4.3. Implementing equals() and hashCode()
那么,回到最初的问题:
@Transient
属性很可能不是这样的键的一部分。List
、Map
、Set
之前分配值。@Transient
和transient
的两种典型用法我知道的是,要么用于不能被序列化/持久化的东西(例如远程资源句柄),要么用于可以从其他属性重建的计算属性。
对于计算数据,在等式关系(equals/hashCode
)中使用它们没有意义,因为那会是多余的。该值是由其他已在等式中使用的值计算出来的。但仍然有可能在toString
中打印它们(例如基础价格和比率用于计算实际价格)。
对于不可序列化/可持久化数据,情况取决于具体情况。我可以想象一个不可序列化的资源句柄,但您仍然可以比较句柄所代表的资源名称。同样,在toString
中,打印句柄资源名称可能也是有用的。
这是我的个人看法,但如果您解释一下@Transient
的具体用途,或许有人能给出更好的建议。
异常可能来自于将其设置为transient
,同时您提供了writeObject()
和readObject()
用于处理它。