Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么在使用乘法值遍历一个bucket时只调用一次hashCode()?_Java_Equals_Hashcode - Fatal编程技术网

Java 为什么在使用乘法值遍历一个bucket时只调用一次hashCode()?

Java 为什么在使用乘法值遍历一个bucket时只调用一次hashCode()?,java,equals,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 vo

我有一节以下的课

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);
    }
据我所知,由于哈希代码的原因,所有这些值都应该在一个bucket中。在最后一次调用map.getan时,根据控制台,hashCode只被调用一次,但在通过bucket进行迭代并找到具有正确hashCode的条目时,是否应该多次调用它


EDIT1:如果我使用控制台日志记录实现equals,则不会再次根据控制台调用它,仅当有两个对象具有相同的哈希代码时才会调用它,例如,如果我将其添加到我的代码映射中。putnew Animal16*3,4;,在这种情况下,当从map获取对象时,hashCode会被调用两次。

否,hashCode用于查找bucket,这需要在map.getan参数上调用一次hashCode


然后将bucket中的元素与equals进行比较,以找到正确的对象。

否,hashcode用于查找bucket,这需要对map.getan参数调用的hashcode进行一次调用


然后将bucket中的元素与equals进行比较,以找到正确的对象。

单个bucket可能包含具有不同hashCode的键,并且将相关bucket的键的hashCode与您正在添加/搜索的键进行比较。但是,hashCode缓存在Map.Entry中,因此无需为映射中已经存在的Entry调用键的hashCode方法:


哈希值与缓存的密钥哈希值进行比较,这意味着无需再次调用哈希代码。

单个bucket可能包含具有不同哈希代码的密钥,并且相关bucket的密钥哈希代码与您正在添加/搜索的密钥进行比较。但是,hashCode缓存在Map.Entry中,因此无需为映射中已经存在的Entry调用键的hashCode方法:


哈希值与缓存的密钥哈希值进行比较,这意味着无需再次调用哈希代码。

最多可以期望调用哈希代码。调用次数是HashMap的一个实现细节,您不应该期望有任何特定的行为,也不应该期望观察到的行为是稳定的。由于hashCode的实现方式可能不同,甚至代价高昂,因此只调用一次是合理的选择,即使需要多次调用,也可以使用返回值而不是对hashCode的新调用。然而,这仅仅是猜测,不应该假设。

最多可以期望调用hashCode。调用次数是HashMap的一个实现细节,您不应该期望有任何特定的行为,也不应该期望观察到的行为是稳定的。由于hashCode的实现方式可能不同,甚至代价高昂,因此只调用一次是合理的选择,即使需要多次调用,也可以使用返回值而不是对hashCode的新调用。然而,这只是猜测,不应该假设。

每个人都已经回答了这个问题。我想从HashMap中捕获代码以提供更多信息

当我们从Map调用.put时,它们首先在内部调用hashKey

在hash方法中,您将看到hashCode被调用

然后在putVal方法中,有两个位置等于get,如下所示

这就是为什么我们会多次调用hashCode


如果您需要了解更多信息,请查看此链接以了解HashMap的实现

每个人都已经回答了问题。我想从HashMap中捕获代码以提供更多信息

当我们从Map调用.put时,它们首先在内部调用hashKey

在hash方法中,您将看到hashCode被调用

然后在putVal方法中,有两个位置等于get,如下所示

这就是为什么我们会多次调用hashCode


请检查此链接以了解HashMap的实现,如果您需要了解更多内容,则在确定bucket后,HashMap将使用.eqauls来确定与提供的对象匹配的链表节点。见实施:

/**
 * Implements Map.get and related methods
 *
 * @param hash hash for key
 * @param key the key
 * @return the node, or null if none
 */
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 && // always check first node
            ((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 &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}

一旦确定了bucket,HashMap将使用.eqauls来确定与提供的对象匹配的链表节点。见实施:

/**
 * Implements Map.get and related methods
 *
 * @param hash hash for key
 * @param key the key
 * @return the node, or null if none
 */
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 && // always check first node
            ((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 &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}
map.putnew Animal16*i,i

执行此操作时,Animal对象是key,其哈希值将是值i所在的bucket。把它想象成地图上甚至没有存储的动物对象

当您添加所有9项时,具有值的存储桶为0,16,32,48,…,16*8

当您执行map.getaa时,将从64的对象返回一个的哈希

tl;dr所有对象都属于不同的存储桶,因为它们的哈希值不同

执行此操作时,Animal对象是key,其哈希值将是值i所在的bucket。把它想象成动物的物体是不可能的 甚至存储在地图中

当您添加所有9项时,具有值的存储桶为0,16,32,48,…,16*8

当您执行map.getaa时,将从64的对象返回一个的哈希


tl;dr所有对象都属于不同的bucket,因为它们的hashvalue是不同的

注意,您没有实现equals。为什么您认为它们都应该在同一个bucket中?您创建的动物实例大多具有不同的哈希代码值,为什么它们会有哈希冲突?除此之外:哈希映射缓存它存储的键的哈希代码,因此在添加它们时,它只需要对其键调用一次哈希代码。@JoachimSauer index_of_bucket=hashCodekey&n-1,我的哈希代码是0、16、32。。。默认情况下,地图的大小为16@BogdanTimofeev:这不是Java HashMap使用哈希的方式,它实际上是在使用哈希之前对其进行操作。检查您最喜欢的JVM实现中的private HashMap.hashObject方法。请注意,您没有实现equals。为什么您认为它们都应该在同一个bucket中?您创建的动物实例大多具有不同的哈希代码值,为什么它们会有哈希冲突?除此之外:哈希映射缓存它存储的键的哈希代码,因此在添加它们时,它只需要对其键调用一次哈希代码。@JoachimSauer index_of_bucket=hashCodekey&n-1,我的哈希代码是0、16、32。。。默认情况下,地图的大小为16@BogdanTimofeev:这不是Java HashMap使用哈希的方式,它实际上是在使用哈希之前对其进行操作。检查您最喜欢的JVM实现中的private HashMap.hashObject方法。不调用equals也请参见我的编辑1,看起来没有冲突all@BogdanTimofeev如果没有必要的话就不打电话了。这个问题是关于冲突还是关于何时使用equals和hashCode?equals没有被调用也请参见我的编辑1,看起来在这里没有冲突all@BogdanTimofeev如果没有必要的话就不打电话了。这个问题是关于冲突还是关于何时使用equals和hashCode?
/**
 * Implements Map.get and related methods
 *
 * @param hash hash for key
 * @param key the key
 * @return the node, or null if none
 */
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 && // always check first node
            ((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 &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}