我正在使用带有java.util.Set实现的java.util.HashSet接口并将其存储在Map中。
我将一个对象添加到Set然后再次检索Set对象,并且能够添加另一个与第一个对象相同的对象。
当添加看似相等的对象时,Set.add返回true
,并且两个相等的对象存储在HashSet中。这怎么可能,我该怎么做才能解决Set合约的明显破坏?
我通过IntelliJ IDEA 2018.3.6使用Java 12,并检查了我添加到Set的两个对象的类的java.lang.Object.hashCode实现,两者都返回相同的哈希码。我还检查了java.lang.Objects.equals实现,并在使用该方法检查它们的相等性时返回true
。两个对象都包含在另一个对象Entity中,但只转发对象的hashCode
和equals
实现。
class Model {
...
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Offer)) {
return false;
}
Offer offer = (Offer) obj;
return Objects.equals(id, offer.id)
&& Objects.equals(name, offer.name)
;
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + Objects.hashCode(id);
result = 31 * result + Objects.hashCode(name);
return result;
}
...
}
class Store {
...
private static class Entry {
Object value;
Entry(Object value) {
this.value = value;
}
Object getValue() {
return value;
}
@Override
public boolean equals(Object obj) {
return Objects.equals(value, obj);
}
@Override
public int hashCode() {
return value.hashCode();
}
@Override
public String toString() {
return "Entry[value = " + value + "]";
}
}
...
private Map<Class<?>, Set<Entry>> data;
...
private Set<Entry> get(Class<?> type) {
return data.getOrDefault(type, new HashSet<>());
}
@Override
public void persist(Object obj) {
Entry entry = new Entry(obj);
Set<Entry> objects = get(obj.getClass());
if (objects == null) {
objects = new HashSet<>();
}
if (!objects.add(entry)) {
throw new ObjectExistsException
("Object already exists: " + obj);
}
data.put(obj.getClass(), objects);
}
...
}
当模型类型的obj1
和obj2
相等且objects
已经包含在Entry对象中包含的obj1
时,我预计当obj2
被包裹在objects
中时obj2
不被添加到entry
而objects.add(entry)
返回false
然后抛出ObjectExistsException。
然而,实际发生的是objects.add(entry)
返回true
和包裹在obj2
的entity
被添加到objects
。
@Override
public boolean equals(Object obj) {
return Objects.equals(value, obj);
}
这不是Entry.equals
的正确实现。这可能会将Entry
与当前条目持有的值进行比较。 (比如将信件与信封进行比较)。
让你的equals方法检查obj
是一个Entry
,并获得它的值,并检查相等。
你是对的@Andy Turner,但正是@Andreas指出了我正确的方向。我以为我会懒,而不是写一个完整的equals
方法实现,但它花了我。应该是这样的:
private static class Entry {
...
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Entry)) {
return false;
}
Entry entry = (Entry) obj;
return Objects.equals(getValue(), entry.getValue());
}
...
}
谢谢你们俩。