[英]Is it a bad practice to return super.equals and super.hashcode in a class?
假设我有这门课:
public class Person {
private Integer idFromDatabase;
private String name;
//Getters and setters
}
字段idFromDatabase
是应在 equals 中验证并用于创建 hashCode 的属性。 但有时,我正在处理内存中的 People 列表,并且尚未将对象存储在数据库中,因此所有对象的idFromDatabase
为 null,这将导致 hashCode 为每个对象返回相同的值。 我通过在 equals 和 hashCode 方法中添加以下内容解决了这个问题:
if(idFromDatabase == null) return super.equals(o);
和
if(idFromDatabase == null) return super.hashCode();
它有效,但安全吗? 我可以为每个依赖数据库字段进行相等性检查的类都这样做吗?
if(idFromDatabase == null) return super.equals(o);
不正确,因为 super 的 equals (如果正确实现)会执行getClass()
检查,这当然会有所不同,因此super.equals
将始终为 false。
根据您的描述,我推断在比较两个People
对象时:
如果这是正确的,那么:
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (this.idFromDatabase == null)
return false;
if (! (obj instanceof People))
return false;
People that = (People)obj;
if (that.idFromDatabase == null)
return false;
return this.idFromDatabase.equals(that.idFromDatabase);
}
@Override
public int hashCode() {
// Use super.hashCode to distribute objects without an idFromDatabase
return (this.idFromDatabase != null ? this.idFromDatabase.hashCode() : super.hashCode());
}
正如@Jeroen Vannevel 已经指出的那样,如果您最终可能有 2 个或更多对象未存储在包含完全相同信息的数据库中,那么此技术将无法帮助您识别这一点。
@Solver 也是正确的,因为子类的行为与其超类不同,因此您不应该返回它们相等。
但是,在您的特定示例中,您只是扩展了Object
类,因此您认为它是安全的假设是正确的(如果我们排除内存中有 2 个尚未持久化的相同Person
的可能性)。
Object
提供了最基本的equals 方法:
对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象(
x == y
的值为true
)时,此方法才返回 true 。
Object 的hashCode 方法:
尽管合理可行,[...] 确实为不同的对象返回不同的整数
这些定义清楚地表明,如果您只是扩展Object
,那么这种技术是安全的。
你的推理有一些问题。
equals
和hashcode
不是子类型友好的,所以开始考虑super
调用是没有意义的,super
是Object
所以它是equals
和hashcode
在这种情况下是无用的。Person
对象引用同一个人,但只有一个存储在数据库中,该怎么办? 它们是相同的还是不同的?一种通用的解决方案是创建两个类
Person
存储“本地”的人。 不包含idFromDatabase
,StoredPerson
含有idFromDatabase
和一个Person
(或所有领域的Person
,但是这是难以维护) 这样,至少equals
和hashcode
码在任何时候都是明确定义和表现良好的。
如果您使用任何类型的Set
/ Map
来存储人员,那么您现在拥有其中的两个。 当您将新Person
保存到数据库时,您将它们从“本地” Set
/ Map
中StoredPerson
,将它们包装在StoredPerson
,然后将它们放入“数据库” Set
/ Map
。
如果您想要一个所有人的可搜索列表,请将两个数据集中的所有Person
合并为一个。 当您找到您感兴趣的Person
并想要检索idFromDatabase
(如果有),那么您最好事先准备好从Person
到StoredPerson
的映射。
因此你至少需要,
Set<Person> localPeople = new HashSet<>();
Map<Person, StoredPerson> storedPeople = new HashMap<>();
和这样的事情:
void savePerson(Person person) {
synchronized (lockToPreserveInvariants) {
int id = db.insert(person);
StoredPerson sp = new StoredPerson(id, person);
localPeople.remove(person);
storedPeople.put(person, sp);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.