Java 在类中返回super.equals和super.hashcode是一种不好的做法吗?
假设我有一门课:Java 在类中返回super.equals和super.hashcode是一种不好的做法吗?,java,Java,假设我有一门课: public class Person { private Integer idFromDatabase; private String name; //Getters and setters } 字段idFromDatabase是应在equals中验证并用于创建哈希代码的属性。但有时,我处理内存中的人员列表,但尚未将对象存储在数据库中,因此idFromDatabase对于所有对象都为空,这将导致hashCode为每个对象返回相同的值。 我通过在eq
public class Person {
private Integer idFromDatabase;
private String name;
//Getters and setters
}
字段idFromDatabase
是应在equals中验证并用于创建哈希代码的属性。但有时,我处理内存中的人员列表,但尚未将对象存储在数据库中,因此idFromDatabase
对于所有对象都为空,这将导致hashCode为每个对象返回相同的值。
我通过在equals和hashCode方法中添加以下内容来解决此问题:
if(idFromDatabase == null) return super.equals(o);
及
它起作用了,但安全吗?我可以为依赖数据库字段进行相等性检查的每个类执行此操作吗?
如果(idFromDatabase==null)返回super.equals(o)
是不正确的,因为super的equals(如果实现正确)执行了getClass()
检查,这当然会有所不同,因此super.equals
将始终为false。如果(idFromDatabase==null)返回super.equals(o)
是不正确的,因为super的equals(如果实现正确)执行了getClass()
检查,这当然是不同的,因此super.equals
将始终是错误的。根据您的描述,我推断,在比较两个人
对象时:
- 如果两者都有一个ID,那么如果它们有相同的ID,即使它们有不同的名称,它们也是相等的
- 否则,只有当它们是同一实例时,它们才相等
@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());
}
根据您的描述,我推断,当比较两个
人
对象时:
- 如果两者都有一个ID,那么如果它们有相同的ID,即使它们有不同的名称,它们也是相等的
- 否则,只有当它们是同一实例时,它们才相等
@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所指出的,如果您最终可能会有两个或多个对象没有存储在数据库中,而这些对象包含完全相同的信息,那么这种技术将无法帮助您识别这些信息 @解算器也非常正确,因为子类的行为与其父类不同,所以您不应该返回它们相等的结果 但是,在您的特定示例中,您只是扩展了
对象
类,因此您认为它是安全的假设是正确的(如果我们排除内存中有两个尚未持久化的人
的可能性)
对象
提供了最基本的:
对于任何非空引用值x和y,此方法返回true
当且仅当x和y引用同一对象
(x==y
的值为true
)
对象的名称:
尽可能实际,[…]会为不同的对象返回不同的整数
这些定义清楚地表明,如果您只扩展
对象
,那么这种技术是安全的。正如@Jeroen Vannevel所指出的,如果您可能最终有两个或多个对象没有存储在数据库中,而数据库中包含完全相同的信息,那么这种技术将无法帮助您识别这一点
@解算器也非常正确,因为子类的行为与其父类不同,所以您不应该返回它们相等的结果
但是,在您的特定示例中,您只是扩展了对象
类,因此您认为它是安全的假设是正确的(如果我们排除内存中有两个尚未持久化的人
的可能性)
对象
提供了最基本的:
对于任何非空引用值x和y,此方法返回true
当且仅当x和y引用同一对象
(x==y
的值为true
)
对象的名称:
尽可能实际,[…]会为不同的对象返回不同的整数
这些定义清楚地表明,如果您只扩展
对象
,那么这种技术是安全的。您的推理存在一些问题
和equals
不是子类型友好的,因此开始考虑hashcode
调用是没有意义的super
无论如何都是super
,因此它的对象
,等于
在这个上下文中是无用的hashcode
- 如果有两个
对象引用同一个人,但数据库中只存储一个,该怎么办。它们是相同的还是不同的Person
Person
用于存储“本地”人员。不包含idFromDatabase
StoredPerson
,其中包含idFromDatabase
和Person
(或Person
的所有字段,但这更难维护)equals
和hashcode
在任何时候都是定义良好、行为良好的
实施和使用
如果您使用任何类型的集合
/地图
来存储人员,您现在有两个。当您将新的人员
保存到数据库时,您可以将其从“本地”集合
/映射
中删除,将其包装在存储人员
中,并将其放入“数据库”集合
/映射
如果您想要所有人的可搜索列表,请将两个数据集中的所有Person
s合并为一个。当您找到感兴趣的人
并想从数据库中检索idFromDatabase
时,如果有,您最好事先准备一张从人
到StoredPerson
的地图
所以你至少需要
Set<Person> localPeople = new HashSet<>();
Map<Person, StoredPerson> storedPeople = new HashMap<>();
你的推理有几个问题
和equals
不是子类型友好的,因此开始考虑hashcode
调用是没有意义的super
是super
所以它是对象
相等的
void savePerson(Person person) { synchronized (lockToPreserveInvariants) { int id = db.insert(person); StoredPerson sp = new StoredPerson(id, person); localPeople.remove(person); storedPeople.put(person, sp); } }