java - 为什么 hashCode() 在遍历具有乘法值的桶时被调用一次?

标签 java equals hashcode

我有一个跟类

public class Animal {

    private int hash;

    public Animal(int hash) {
        this.hash = hash;
    }

    @Override
    public int hashCode() {
        System.out.println(hash);
        return hash;
    }
}

还有这段代码

    public static void main(String[] args) {
        Map<Animal, Integer> map = new HashMap<>();
        for (int i = 0; i < 4; i++) {
            map.put(new Animal(16 * i), i);
        }

        Animal an = new Animal(16*4);
        map.put(an, 1);

        for (int i = 5; i < 9; i++) {
            map.put(new Animal(16 * i), i);
        }
        Integer value = map.get(an);
    }

据我所知,所有这些值都应该在一个桶中(由于它们的哈希码)。在最后一次调用 map.get(an) 时,hashCode() 只被调用一次(根据控制台),但在遍历 bucket 并找到一个正确的条目时不应该调用多次哈希码()?

EDIT1:如果我实现equals(使用控制台日志记录),它也不会被调用(再次根据控制台),只有当有两个对象具有相同 哈希码(例如,如果我将此添加到我的代码 map.put(new Animal(16*3), 4);,在这种情况下,hashCode() 被调用 两次 从 map 获取对象时)。

最佳答案

单个桶可能包含具有不同 hashCode 的键, 和 hashCode将相关存储桶的键与您正在添加/搜索的键进行比较。然而,hashCode缓存在 Map.Entry 中,因此无需调用 key 的 hashCode Entry 的方法已经在 Map 中的 s :

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;

    Node(int hash, K key, V value, Node<K,V> next) {
        this.hash = hash; // here the hash code is cached
        this.key = key;
        this.value = value;
        this.next = next;
    }
    ...
}

不过,这是一个实现细节。

您可以在此处看到用于定位 Entry 的代码对于给定的 hashkey :

final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        if (first.hash == hash && // <--- here a cached hash is compared to hash
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        if ((e = first.next) != null) {
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            do {
                if (e.hash == hash &&  // <--- here a cached hash is compared to hash
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}

hash与缓存的 hash 进行比较键的值,这意味着不需要调用 hashCode()再次。

关于java - 为什么 hashCode() 在遍历具有乘法值的桶时被调用一次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58319650/

相关文章:

java - 将 JTable 用作 JList

java - 较短的等于方法与较长的等于方法相同吗?

java - 重写自定义类的哈希码和等于

.net - 覆盖 GetHashCode 的最佳算法是什么?

java - 在二维数组中查找相似行的代码

java - 无法读取在java中使用SXSSFWorkbook编写的文件

java - 无法在 Osgi Blueprint 中动态绑定(bind)服务

Java 重写 hashCode() 得到 StackOverflowError

java - 在android中显示区域字符

java - 我不明白这个 ("string"== "string") 例子