Java:为什么在hashmap中搜索相同的变量时不调用equal方法

时间:2014-04-25 12:56:49

标签: java

这是我的测试课..

import java.util.HashMap;

public class Test {

    public static void main(String[] args) {
        A a = new A(0, 1);
        HashMap<A, Integer> map = new HashMap<A, Integer>();
        map.put(a, (a.x + a.y));
        System.out.println(map.containsKey(a));
        System.out.println("----------------- ");
        System.out.println(map.containsKey(new A(0, 1)));
    }

}

这是我的A类,其中包含hashcode和eclipse生成的相等方法。

class A {
    int x, y;

    public A(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        System.out.println(" in hashcode");
        final int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        System.out.println(" in equal");
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        A other = (A) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }

}

程序的输出是

 in hashcode
 in hashcode
true
----------------- 
 in hashcode
 in equal
true

我的问题是:(我知道哈希码的合同和等号以及为什么使用它)

  1. 为什么在第一种情况下hashcode方法被称为twise?
  2. 为什么在第一种情况下没有调用? JVM如何知道它与我们搜索的变量相同?

3 个答案:

答案 0 :(得分:9)

1)调用put时调用getHashCode,调用contains时调用getHashCode。

2)在第一种情况下,hashmap包含对a的引用,即内存中的地址,因此不需要调用equals。在第二种情况下,表查找找到a,但这是与您作为参数提供的新A不同的对象,因此需要调用equals()以查明它们是否相等(它们可能不同)并且具有相同的哈希码,这将是一次冲突。)

答案 1 :(得分:4)

如果你看一下HashMap.containsKey的源代码,你会发现以下内容(取自这里:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/HashMap.java#HashMap.containsKey%28java.lang.Object%29

public boolean containsKey(Object key) {
    return getEntry(key) != null;
}


final Entry<K,V> getEntry(Object key) {
    int hash = (key == null) ? 0 : hash(key.hashCode());
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
    e != null;
    e = e.next) {
        Object k;
        if (e.hash == hash &&
        ((k = e.key) == key || (key != null && key.equals(k))))
        return e;
    }
    return null;
}

重要的部分是(k = e.key) == key || (key != null && key.equals(k))。 metod首先通过引用比较关键对象,然后使用equals方法进行比较,但前提是引用不同。

在您第一次调用containsKey时,关键引用将是相同的(同一个对象)。在第二个调用中,引用将是不同的(&#34;等于&#34;对象的不同实例),因此调用equals

答案 2 :(得分:2)

您可以在@ kresimir-nesek粘贴代码中查看

首先获取hashCode:int hash = (key == null) ? 0 : hash(key.hashCode());并在哈希码中打印

然后比较java对象标识符(k = e.key) == key

1)在第一种情况下是相同的并返回true。调用map.put,您将获得哈希码中的第二个

2)但在第二种情况下,对象标识符是不同的,所以调用equals(... (key != null && key.equals(k)) ...)

“相等”