[英]Is it a bad practice to return super.equals and super.hashcode in a class?
Let's say i have this class:假设我有这门课:
public class Person {
private Integer idFromDatabase;
private String name;
//Getters and setters
}
The field idFromDatabase
is the attribute that should be verified in equals and used to create the hashCode.字段idFromDatabase
是应在 equals 中验证并用于创建 hashCode 的属性。 But sometimes, i am working with a list of People in memory, and have not yet stored the objects on the database, so the idFromDatabase
is null for all objects, which would cause hashCode to return the same value for every object.但有时,我正在处理内存中的 People 列表,并且尚未将对象存储在数据库中,因此所有对象的idFromDatabase
为 null,这将导致 hashCode 为每个对象返回相同的值。 I solved this issue by adding the following to equals and hashCode metods:我通过在 equals 和 hashCode 方法中添加以下内容解决了这个问题:
if(idFromDatabase == null) return super.equals(o);
and和
if(idFromDatabase == null) return super.hashCode();
It worked, but is it safe?它有效,但安全吗? Can i do it for every class that relies on a database field for equality check?我可以为每个依赖数据库字段进行相等性检查的类都这样做吗?
if(idFromDatabase == null) return super.equals(o);
is incorrect as super's equals (if implemented correctly) does a getClass()
check, which will of course be different, thus super.equals
will always be false.不正确,因为 super 的 equals (如果正确实现)会执行getClass()
检查,这当然会有所不同,因此super.equals
将始终为 false。
From your description I'm inferring that when comparing two People
objects:根据您的描述,我推断在比较两个People
对象时:
If that's correct, then:如果这是正确的,那么:
@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());
}
As already noted by @Jeroen Vannevel, if you are likely to end up with having 2 or more objects not stored in database holding the exact same information, then this technique will not help you in identifying this.正如@Jeroen Vannevel 已经指出的那样,如果您最终可能有 2 个或更多对象未存储在包含完全相同信息的数据库中,那么此技术将无法帮助您识别这一点。
@Solver is also quite true in that a subclass is meant to have different behavior than its superclass, so you shouldn't return that they're equal. @Solver 也是正确的,因为子类的行为与其超类不同,因此您不应该返回它们相等。
However, in your particular example, you are just extending the Object
class, so your assumption that it is safe is true (if we exclude the possibility of having 2 not-yet-persisted same Person
s in memory).但是,在您的特定示例中,您只是扩展了Object
类,因此您认为它是安全的假设是正确的(如果我们排除内存中有 2 个尚未持久化的相同Person
的可能性)。
Object
provides the most basic equals method : Object
提供了最基本的equals 方法:
For any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (
x == y
has the valuetrue
).对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象(x == y
的值为true
)时,此方法才返回 true 。
The hashCode method of Object: Object 的hashCode 方法:
As much as is reasonably practical, [...] does return distinct integers for distinct objects尽管合理可行,[...] 确实为不同的对象返回不同的整数
These definitions make it clear that if you're only extending Object
, then this technique is safe.这些定义清楚地表明,如果您只是扩展Object
,那么这种技术是安全的。
There are a few problems with your reasoning.你的推理有一些问题。
equals
and hashcode
are not subtype-friendly so it doesn't make sense to start thinking about super
calls, equals
和hashcode
不是子类型友好的,所以开始考虑super
调用是没有意义的,super
is Object
anyway so it's equals
and hashcode
are useless in this context.无论如何super
是Object
所以它是equals
和hashcode
在这种情况下是无用的。Person
objects referring to the same person, but only one is stored in the database.如果您有两个Person
对象引用同一个人,但只有一个存储在数据库中,该怎么办? Are they the same or different?它们是相同的还是不同的?One universal solution is to make two classes一种通用的解决方案是创建两个类
Person
which stores a 'local' person. Person
存储“本地”的人。 Doesn't contain idFromDatabase
,不包含idFromDatabase
,StoredPerson
which contains idFromDatabase
and a Person
(or all fields of Person
, but this is harder to maintain) StoredPerson
含有idFromDatabase
和一个Person
(或所有领域的Person
,但是这是难以维护) This way, at least equals
and hashcode
are well-defined and well-behaved at all times.这样,至少equals
和hashcode
码在任何时候都是明确定义和表现良好的。
If you use any kind of Set
/ Map
to store people, you now have two of them.如果您使用任何类型的Set
/ Map
来存储人员,那么您现在拥有其中的两个。 When you save new Person
s to database, you remove them from the 'local' Set
/ Map
, wrap them in StoredPerson
, and put them in the 'database' Set
/ Map
.当您将新Person
保存到数据库时,您将它们从“本地” Set
/ Map
中StoredPerson
,将它们包装在StoredPerson
,然后将它们放入“数据库” Set
/ Map
。
If you want a searchable list of all people, make one with all Person
s from both datasets into one.如果您想要一个所有人的可搜索列表,请将两个数据集中的所有Person
合并为一个。 When you find a Person
you're interested in and want to retrieve the idFromDatabase
, if any, then you'd do good to prepare a map from Person
to StoredPerson
beforehand.当您找到您感兴趣的Person
并想要检索idFromDatabase
(如果有),那么您最好事先准备好从Person
到StoredPerson
的映射。
Thus you need at least,因此你至少需要,
Set<Person> localPeople = new HashSet<>();
Map<Person, StoredPerson> storedPeople = new HashMap<>();
and something like this:和这样的事情:
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.