assertEquals(def.getMengs(), exp.getMengs());
失败,报告: 期待:java.util.HashSet< [...所以geht死Legende ......传说有...]>但是:java.util.HashSet< [...所以geht死Legende ......传说有...]>
实际上,通过调试器,我看到两个集合只包含一个含义,objId = 1。 我期望在Meaning类(@Entity)中使用以下代码来保证上述代码的工作原理。
@Override
public boolean equals(Object object) {
if (!(object instanceof Meaning)) {
return false;
}
Meaning other = (Meaning) object;
if (other != null && objId == other.objId) return true;
return false;
}
@Override
public int hashCode() {
int hash = 7;
hash = 67 * hash + this.objId;
return hash;
}
确实,这个测试通过了:
db.insert(admin);
final Meaning meng = new Meaning(admin, new Expression("essen"));
meng.setObjId(11);
final Meaning meng1 = new Meaning(admin, new Expression("mangiare"));
meng1.setObjId(11);
assertEquals(meng,meng1);
那么我的问题可能是什么? Thery都是HashSets,它们都具有相同的大小,并且它们内部的对象相等。确实
assertEquals(def.getMengs().iterator().next(), exp.getMengs().iterator().next());
在它过去之前。然而,这不会(但我不知道为什么):
assertTrue(def.getMengs().containsAll(exp.getMengs()));
所以,这就是问题所在。
这是测试代码:
try{
db.insertWords(toEnumMap(mengs[i],admin));
}catch(Exception e){
fail(e.getMessage());
}
final Expression exp = db.get(Expression.class, mengs[i][0]);
testGender(exp, mengs[i][2]);
final Expression def = db.get(Expression.class, mengs[i][1]);
assertNotNull(def);
assertEquals(def.getMengs().iterator().next(), exp.getMengs().iterator().next());
assertEquals(exp.getMengs().size(), def.getMengs().size());
assertTrue(def.getMengs().containsAll(def.getMengs()));
assertTrue(def.getMengs().containsAll(exp.getMengs()));
assertEquals(def.getMengs(), exp.getMengs());
db.get只包装em.find。 InsertWords应该持久化def和exp。
public void insertWords(EnumMap<Input, MemoEntity> input) throws MultipleMengsException {
insert(input.get(Input.expression)); //INSERT OR IGNORE
final boolean isNewDef = insert(input.get(Input.definition));
final Expression def = get(Expression.class, input.get(Input.definition).getId());
final Expression exp = get(Expression.class, input.get(Input.expression).getId());
final MUser usr = get(MUser.class, input.get(Input.user).getId());
final Set<Meaning> mengs = getMengs(usr,def,isNewDef);
if (mengs == null) {//is new to the user
final Meaning meng = new Meaning(usr, exp, def);
insert(meng);
} else { //old meaning
if (mengs.size() > 1) throw new MultipleMengsException(mengs);
else{
final Meaning meng = mengs.iterator().next();
meng.addExp(exp);
meng.setLastPublishedDate(null); //reschedule
}
}
Logger.getAnonymousLogger().log(Level.INFO, "inserted pair <{0},{1}>", new String[]{exp.getExpression(), def.getExpression()});
}
public boolean insert(final MemoEntity entity) {
if (em.find(entity.getClass(), entity.getId()) == null) {
et.begin();
em.persist(entity);
et.commit();
return true;
}
return false;
}
public <MemoEntity> MemoEntity get(final Class<MemoEntity> entityClass, final Object primaryKey) {
return em.find(entityClass, primaryKey);
}
答案 0 :(得分:3)
实体的HashCode和equals最好不使用代理ID进行比较,而是使用对象的业务属性或仅使用自然键来实现比较。有关详细信息,请参阅此SO question。
编辑:至于为什么这不起作用,我唯一的猜测是你在将对象添加到HashSet后修改对象,特别是更改ID。这将导致contains方法失败,因为它使用hashCode将对象定位为hashmap中的键,如果ID已更改,它将查找底层hashMap中的错误位置。
答案 1 :(得分:1)
如果
assertTrue(def.getMengs().containsAll(exp.getMengs()));
通过,那么最可能的解释是def.getMengs()
包含来自exp.getMengs()
的所有元素加上其他一些不属于后者的元素。
尝试颠倒它,即
assertTrue(exp.getMengs().containsAll(def.getMengs()));
或只是
assertEqual(exp.getMengs().size(), def.getMengs().size());
修改强>
我发现我误读了你的问题。但是,这确实澄清了这种情况。 equals方法检查3件事。 1)两者都是Set
类型。 2)相同大小和3)“a”包含来自“b”的所有元素。
你似乎失败了最后一个。实际上,由于在HashSet上对containsAll
执行自身操作失败,因此必须成为意义上的equals
方法。阅读集合上的containsAll
和contains
方法的代码(Java 6)清楚地表明hashCode
方法不用于此目的。
答案 2 :(得分:1)
你的对象是整数还是长整数?那你的问题可能与equals方法中的autoboxing有关:
objId == other.objId
这将适用于第一次测试中的小常量,因为它们是缓存的。通常,在这种情况下,您应该使用equals方法。 equals方法中的那一行最好写成:
return objId == null ? this == other : objId.equals(other.objId);
答案 3 :(得分:0)
如果你用objId进行散列,那么它不应该是可变的(正如setObjId建议的那样)。特别是,如果您坚持使用该方法,则不应在将对象放入哈希集后调用它。
答案 4 :(得分:0)
您正在使用hibernate实体,因此您不应直接引用成员变量,因为它们可能会从数据库中延迟加载。所以,你的equals / hashCode方法应该使用getObjId()而不是objId。
另外,如另一篇文章所述,如果你的objId是一个对象类型(Integer,Long),你不应该使用“==”。
答案 5 :(得分:-1)
问题是containsAll比较对象的引用(使用==)而不是调用.equals。根据文档,HashSet.equals在内部使用containsAll。
一种可能的解决方案是从HashSet派生自己的类并覆盖containsAll方法。