java - Java 中 HashMap 的奇怪行为

标签 java hashmap hashcode

我在下面的类中发现了 hashmap 的一些奇怪行为。

class Employee {

  private String a;
  private int b;

  public Employee(String a, int b) {
    this.a = a;
    this.b = b;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((a == null) ? 0 : a.hashCode());
    result = prime * result + b;
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Employee other = (Employee) obj;
    if (a == null) {
        if (other.a != null)
            return false;
    } else if (!a.equals(other.a))
        return false;
    if (b != other.b)
        return false;

    return true;
  }

  public static void main(String[] args) {
    HashMap<Employee,Integer> map = new HashMap<>();

    for(int i = 0; i < 13; i++) {
        map.put(new Employee( i + "", i), i + i);
    }
  }
}

当我使用 new Employee( "", i) 作为在 map 中存储数据的键时,它工作正常并在第 12 个节点插入后调整 map 大小。但在使用 new Employee( i+"", i) 作为键,它表现出奇怪的行为,在使用此键添加第 10 个元素时,它将 map 的大小从 16 调整为 32,在添加第 11 个元素时,它再次将 map 的大小从 32 调整为 64。 如果您发现此行为的任何原因,请提供帮助。

最佳答案

原因 - Java 8 中 HashMap 的新组织。当特定 bin 中的列表变得太长时 HashMap将该列表迁移到树而不是链表 - 过程称为 treeifying

TREEIFY_THRESHOLD = 8 表示当在给定的 bin 中有 8 个条目时,给定的 bin 应该将冲突值存储在二叉树中,而不是链表(从而从 O(n)O(log n)

if (binCount >= TREEIFY_THRESHOLD - 1)
                treeifyBin(tab, hash);

方法 treeifyBin 将 bin 中的所有链接节点替换为哈希,除非表太小,在这种情况下它会调整表的大小;

所以在你的情况下,你得到 64 大小(此代码使大小调整两次,将选项卡大小增加到 32 和 64 (MIN_TREEIFY_CAPACITY)):

if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();

关于java - Java 中 HashMap 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43998333/

相关文章:

java - 在不重新启动 Tomcat 的情况下更改配置/设置

java - hibernate:保存没有外键的实体时出现异常

java - 在 Canvas 上设置原点

java - 如何覆盖 HashSet 的 equals()、hashcode() 和 compareTo()

java - 使用已经唯一的整数生成哈希码

Java:列出已插入的相机

java - 如何在 Java 中将 HashMap 转换为 List?

android - 是否可以从一个 HashMap 方法中同时获取 Integer 和 String 值?

Java 使用部分键从 LinkedHashMap 获取值

java - 覆盖 equals 而不是 hashcode 的缺点是什么,反之亦然?