如果我有一个地图和一个对象作为地图键,那么默认的哈希和等于方法是否足够?
class EventInfo{
private String name;
private Map<String, Integer> info
}
然后我要创建一张地图:
Map<EventInfo, String> map = new HashMap<EventInfo, String>();
我是否必须显式实现hashCode()和equals()?感谢。
答案 0 :(得分:6)
是的,你这样做。 HashMap
通过计算密钥的哈希码并将其用作基点来工作。如果hashCode
函数未被覆盖(由您),则它将使用内存地址,equals
将与==
相同。
如果你在Eclipse中,它会为你生成它们。点击来源菜单→生成hashCode()和等于()。
如果您没有Eclipse,那么这里应该有一些功能。 (我在Eclipse中生成了这些,如上所述。)
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((info == null) ? 0 : info.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof EventInfo)) {
return false;
}
EventInfo other = (EventInfo) obj;
if (info == null) {
if (other.info != null) {
return false;
}
} else if (!info.equals(other.info)) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
答案 1 :(得分:3)
是的,您需要它们,否则您将无法比较两个EventInfo(并且您的地图将无效)。
答案 2 :(得分:2)
严格来说,没有。 hashCode()和equals()的默认实现将产生应该工作的结果。见http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode()
我的理解是hashCode()的默认实现是通过在内存中获取对象的地址并转换为整数来实现的,只有当两个对象实际上是同一个对象时,equals()的默认实现才会返回true。 p>
在实践中,您可以(而且应该)改进这两种实现。例如,两种方法都应该忽略不重要的对象成员。另外,equals()可能希望递归地比较对象中的引用。
在您的特定情况下,如果两个对象引用相同的字符串或两个字符串相等并且两个映射相同或相等,则可以将equals()定义为true。我认为WChargin为你提供了很好的实施。
答案 3 :(得分:2)
取决于你想要发生什么。如果具有相同EventInfo
和name
的两个不同info
个实例应生成两个不同的密钥,则您无需实施equals
和hashCode
。
所以
EventInfo info1 = new EventInfo();
info1.setName("myname");
info1.setInfo(null);
EventInfo info2 = new EventInfo();
info2.setName("myname");
info2.setInfo(null);
info1.equals(info2)
会返回false,info1.hashCode()
会返回info2.hashCode()
的不同值。
因此,当您将它们添加到地图时:
map.put(info1, "test1");
map.put(info2, "test2");
您将有两个不同的条目。
现在,这可能是理想的行为。例如,如果您的EventInfo
正在收集不同的事件,则可能希望将具有相同数据的两个不同事件想要成为两个不同的条目。
equals
和hashCode
合同也适用于Set
。
例如,如果您的活动信息包含鼠标点击,那么您可能希望最终得到:
Set<EventInfo> collectedEvents = new HashSet<EventInfo>();
collectedEvents.add(info1);
collectedEvents.add(info2);
2个收集的事件而不仅仅是1 ...
希望我在这里有意义......
编辑:
但是,如果上面的set和map应该只包含一个条目,那么你可以使用apache commons EqualsBuilder和HashCodeBuilder来简化equals
和{{1}的实现}:
hashCode
EDIT2:
如果两个@Override
public boolean equals(Object obj) {
if (obj instanceof EventInfo) {
EventInfo other = (EventInfo) obj;
EqualsBuilder builder = new EqualsBuilder();
builder.append(name, other.name);
builder.append(info, other.info);
return builder.isEquals();
}
return false;
}
@Override
public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder();
builder.append(name);
builder.append(info);
return builder.toHashCode();
}
个实例具有相同的名称,也可能是合适的,例如EventInfo
是一个唯一的标识符(我知道它有点牵强)你的具体对象,但我在这里概括......)