我们说我有这个课程:
public class Person {
private Integer idFromDatabase;
private String name;
//Getters and setters
}
字段idFromDatabase
是应该以等于验证并用于创建hashCode的属性。但有时候,我正在使用内存中的People列表,并且尚未将对象存储在数据库中,因此idFromDatabase
对所有对象都为null,这将导致hashCode为每个对象返回相同的值。
我通过将以下内容添加到equals和hashCode metods来解决了这个问题:
if(idFromDatabase == null) return super.equals(o);
和
if(idFromDatabase == null) return super.hashCode();
它有效,但它安全吗?我是否可以为依赖数据库字段进行相等性检查的每个类执行此操作?
答案 0 :(得分:2)
if(idFromDatabase == null) return super.equals(o);
不正确,因为超级等于(如果正确实施)会进行getClass()
检查,这当然会有所不同,因此super.equals
将始终为假。
答案 1 :(得分:1)
根据您的描述,我推断在比较两个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());
}
答案 2 :(得分:1)
正如@Jeroen Vannevel已经指出的那样,如果你最终可能有2个或更多的对象没有存储在数据库中并保存完全相同的信息,那么这种技术无法帮助你识别它。
@Solver也是如此,因为子类的行为与其超类的行为不同,所以你不应该返回它们是相等的。
但是,在您的特定示例中,您只是扩展了Object
类,因此您认为它是安全的假设是正确的(如果我们排除有2个尚未持久的相同{{1}的可能性在记忆中)。
Person
提供最基本的equals method:
对于任何非空引用值x和y,此方法返回true 当且仅当x和y引用同一个对象时 (
Object
的值为x == y
)。
对象的hashCode method:
尽可能合理,[...]确实为不同的对象返回不同的整数
这些定义清楚地表明,如果您只是扩展true
,那么这种技术是安全的。
答案 3 :(得分:1)
你的推理存在一些问题。
equals
和hashcode
不符合子类型,因此开始考虑super
次来电是没有意义的,super
无论如何都是Object
,所以它equals
和hashcode
在这种情况下无用。Person
个对象引用同一个人,但只有一个存储在数据库中,该怎么办?它们是相同还是不同?一个通用的解决方案是制作两个类
Person
存储了本地'人。不包含idFromDatabase
,StoredPerson
包含idFromDatabase
和Person
(或Person
的所有字段,但这很难维护)这样,至少equals
和hashcode
定义明确,并且始终表现良好。
如果您使用任何类型的Set
/ Map
来存储人,那么您现在有两个人。将新的Person
保存到数据库后,您可以将其从“本地”'中删除。 Set
/ Map
将其封装在StoredPerson
中,并将其放入数据库' Set
/ Map
。
如果您想要一个包含所有人的可搜索列表,请将两个数据集中的所有Person
制成一个。如果您发现自己感兴趣的Person
并想要检索idFromDatabase
(如果有的话),那么您可以自行准备从Person
到{StoredPerson
的地图{1}}事先。
因此至少需要
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);
}
}