【问题标题】:Unable to get right values from hashmap while overriding Hashcode method [duplicate]覆盖哈希码方法时无法从哈希图中获取正确的值[重复]
【发布时间】:2014-12-25 11:24:46
【问题描述】:

在覆盖对象 (BookMe) 的 hashcode 方法后,我正在执行下面的代码。目的是覆盖对象的哈希码,我将在我的地图(哈希图)中将其用作键。但是,执行后我看到空值。地图的实际大小没有问题。下面是代码。如果我不覆盖哈希码方法,我会得到正确的输出(我的意思是所有三个值)。 `

class BookMe{
private String isbn ;
static int i = 0;
public BookMe(String isbn)
{ 
  this.isbn = isbn;     
}
public String getIsbnValue()
{
    return this.isbn;
}
@Override
public boolean equals(Object o)
{
    if(o instanceof BookMe && ((BookMe)o).getIsbnValue() == this.getIsbnValue())
    {
        return true;
    }
    else{
        return false;
    }
}
@Override
public int hashCode()
{
    return this.isbn.toString().length() + (++i);
}

}

公共类 HashMapTest {

public static void main(String[] args) {

    Map<BookMe, Integer> map = new HashMap<BookMe, Integer>();

    BookMe b1 = new BookMe("Graham");
    BookMe b2 = new BookMe("Graham");
    BookMe b3 = new BookMe("Graham");
    map.put(b1, 19);
    map.put(b2, 33);
    map.put(b3, 22);

    System.out.println("----444444--------");
    System.out.println(map.size());

    Set <BookMe> set = map.keySet();
    System.out.println("------*****------");


    for(BookMe bk : set)
    {
        System.out.println("bk : "+ bk);
        System.out.println(map.get(bk));
    }       
}

} `

【问题讨论】:

  • 您正在修改一个静态字段并使用它来影响返回的哈希码。这意味着同一个对象在重复调用时不会给出相同的哈希码。这作为哈希码完全没用。
  • 这可能是您的问题的原因:(BookMe)o).getIsbnValue() == this.getIsbnValue()。请参阅我链接到的问答以获得解释。
  • @Stephen... 我已经进行了更改。我理解错误,有一个被忽略的代码错误,我已更正为“等于”。这不是我的论点。请参阅 Eran 回复中的第三条评论。

标签: java hashmap equals hashcode


【解决方案1】:

您的hashCode 违反了Object::hashCode 的合同。它应该为同一个对象返回相同的值。

来自 Javadoc:

 * <li>Whenever it is invoked on the same object more than once during 
 *     an execution of a Java application, the <tt>hashCode</tt> method 
 *     must consistently return the same integer, provided no information 
 *     used in <tt>equals</tt> comparisons on the object is modified.
 *     This integer need not remain consistent from one execution of an
 *     application to another execution of the same application. 

如果对同一实例的每次调用 hashCode 都返回不同的值,则您不能指望您的 HashMap 找到您的密钥。

如果你想要一个基于 ISBN 的 hashCode,只需返回 ISBN 的 hashCode :

@Override
public int hashCode()
{
    return this.isbn.hashCode();
}

您还应该修复您的 equals 方法:

public boolean equals(Object o)
{
    if(o instanceof BookMe && ((BookMe)o).getIsbnValue().equals(this.getIsbnValue()))
    {
        return true;
    }
    else{
        return false;
    }
}

【讨论】:

  • 我会尝试,但相同字符串的 hashCode(即在我的情况下为 "Graham" )会为我的 BookMe 对象提供相同的重复 hashCode。
  • @MKod 相同 ISBN 的 hashCode 必须给出相同的值。否则,HashMap 将无法使用此 hashCode 定位 BookBe 键。
  • @Eran...我想添加一些东西...如果我不覆盖,我将得到所有三个值,如前所述。我在这里严肃的争论是,每次 put 或 get 都会调用 hashcode,然后它会计算出密钥的唯一性。所以,如果我覆盖或不覆盖,它(哈希码检查)仍然会进入哈希码方法来检查唯一性。话虽如此,为什么它给了我所有三个值(我的意思是当我不覆盖哈希码方法时)?
  • @MKod 当您不覆盖 hashCode 和 equals 时,将使用 Object 类的默认实现。由于 equals 的默认值只是 ==,因此您的 3 个 BookMe 实例被视为唯一键(无论它们是否都具有相同的 hashCode),即使它们都具有相同的 ISBN。
  • 谢谢伊兰。我使用 == 和 equals 做了一些跟踪和错误,使用两个字符串常量和一个没有 NEW 的。我很清楚基本面。
【解决方案2】:

除了 Eran 所说的,即使对于同一个对象,你的哈希码也会返回新的哈希码,比如当你将元素放入 map 和迭代相同的元素时,你应该始终使用 equals 方法比较两个字符串。

((BookMe)o).getIsbnValue() == this.getIsbnValue()

改成:

((BookMe)o).getIsbnValue().equals(this.getIsbnValue())

【讨论】:

    【解决方案3】:

    您的 hashcode 方法已损坏,并且在 equals 方法中,您是通过引用而不是值来比较字符串。你可以像这样更正equals方法

    @Override
    public boolean equals(Object o) {
        return o instanceof BookMe && ((BookMe) o).getIsbnValue().equals(this.getIsbnValue());
    }
    

    要纠正hashcode,可以使用Objects方法生成hashcode

    @Override
        public int hashCode() {
            return Objects.hash(isbn);
        }
    

    此方法的重写实现的一般约定是 它们的行为方式与同一对象的 equals() 一致 方法:给定的对象必须一致地报告相同的哈希 值(除非它被更改以使新版本不再 被认为与旧的“相等”),以及等于()的两个对象 说相等必须报告相同的哈希值。没有要求 哈希值在不同的 Java 实现之间是一致的, 甚至在同一程序的不同执行运行之间,以及 虽然两个不相等的对象具有不同的哈希值是非常可取的, 这不是强制性的(也就是说,实现的散列函数不需要 是一个完美的哈希)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-17
      • 2019-10-04
      • 2013-11-27
      • 2017-05-02
      • 1970-01-01
      相关资源
      最近更新 更多