我需要为一个Item实现equals()方法,该方法可以放在它的Maker的hashset中。Item可以有以下字段
class Item{
private String isbn;
private String name;
private double price;
...
}
class Maker{
private String name;
private Set<Item> items;
public Maker() {
super();
items = new HashSet<Item>();
}
...
}
如果我通过比较三个字段来实现equals并根据这些字段写一个hashCode(),那么我将得到错误的结果
1.add item to hashset
2.modify the price of item
3.try to find if item exists in hashset
@Override
public boolean equals(Object o){
if(o == this){
return true;
}
if (!(o instanceof Item)){
return false;
}
Item a = (Item)o;
if(hasSameName(a) && hasSameIsbn(a) && hasSamePrice(a)){
return true;
}
else{
return false;
}
}
@Override
public int hashCode(){
int hash = 41 + this.isbn.hashCode();
hash = hash*41+ new Double(this.price).hashCode();
hash = hash*41 + this.name.hashCode();
return hash;
}
...
Set<Item> items = new HashSet<Item>();
Item item1 = new Item();
item1.setName("crystal bird");
item1.setIsbn("1111");
item1.setPrice(120.5);
items.add(item1);
System.out.println(items.contains(item1));//returns true
item1.setPrice(177.0);
System.out.println(items.contains(item1));//returns false
解决这个问题的解决方案是什么?我应该使hashCode()仅依赖于isbn并假设它在项目的生命周期内不会改变。
任何帮助表示赞赏
标记。
答案 0 :(得分:5)
是的,ISBN是典型的自然标识符 - 仅用于equals(..)
和hashCode()
答案 1 :(得分:1)
HashSet.add()
方法(基本上是HashMap.put()方法)根据hashcode()
找到自维护内部表的最佳位置。
如果更改Key
中HashMap
项的值,则会更改hashcode()
值,从而导致异常结果。
您只应将ISBN视为对象的关键,以使事情尽可能简单。
@Override
public boolean equals(Object o){
if( o == null ){
return false;
}
if(o == this){
return true;
}
if (!(o instanceof Item)){
return false;
}
Item a = (Item)o;
if( hasSameIsbn(a) ){
return true;
}
else{
return false;
}
}
@Override
public int hashCode(){
return (41 + this.isbn.hashCode());
}
答案 2 :(得分:1)
在你可能错过的API的某个地方有一个黄金法则:
当对象在HashMap / Set中时,不能更改hashCode!
HashMap / Set使用hashCode以更快的方式排列和查找对象。所以你需要提供一个不会改变的hashCode。 hashCode在每种情况下都不需要是唯一的,但如果是,它将提供更好的访问时间。
其他人已经提出了解决方案:使用ISBN作为hashCode。我提供了一个非常好的独特性,不会改变!
答案 3 :(得分:0)
是的,因为您的价格是hashCode计算的一部分,并且其中评估了对象的相等性,当您设置不同的价格时,它的哈希码会发生变化,因此您无法找到相同的项目。 contains()方法使用equals()来检查一个集合是否包含相同的对象,并且由于你的价格是修改后的等式检查的一个因素,因此不再相等,因此contains()无法找到它