java - 尽管 HashMap 是一个无序集合,但为什么它会自动对字符类型键进行排序?

标签 java hashmap

我创建了一个小代码示例来演示 HashMap 和 TreeMap 的区别。

public class HashMapSimpleValueAutosort {

    private static final char[] alphabet = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};

    public static void main(String[] args) {

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

        inverseAbc(map, "HashMap");

        map = new TreeMap<>();

        inverseAbc(map, "TreeMap");
    }

    private static void inverseAbc(Map<Character, Integer> map, String desc ) {

        System.out.println(desc);

        for (int i=25; i>=0; --i) {
            map.put(alphabet[i], 26 - i);
        }
        System.out.println(map);
    }

}

它的作用是使用 HashMap 和 TreeMap 方法将映射内的字母按相反顺序指定为键,并将它们在字母表中的位置指定为相应的值。

尽管键是按相反顺序插入的,但 HashMap toString() 却按升序输出它们,就像 TreeMap 一样。

所以这里出现的问题是:

HashMap 的 toString() 方法在返回映射的字符串表示之前是否在内部对键进行排序?

编辑:

这似乎是基于 JDK 或 IDE 的症状,并且不仅仅限于 toString()。

public class HashMapSimpleValueAutosort {

    private static final char[] alphabet = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};

    public static void main(String[] args) {

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

        printEntries(map, "HashMap");

        map = new TreeMap<>();

        printEntries(map, "TreeMap");
    }


    private static void printEntries(Map<Character, Integer> map, String desc) {

        System.out.println(desc);

        for (int i=25; i>=0; --i) {
            map.put(alphabet[i], 26 - i);
        }

        System.out.print("{ ");
        for (Map.Entry<Character, Integer> entry : map.entrySet()) {
            System.out.printf("%c=%d,", entry.getKey(), entry.getValue());
        }
        System.out.println(" }");
    }

}

在上面的示例中,我将键值对打印为条目。

最佳答案

这是 HashMap 实现的一个奇怪的结果。

HashMap 必须决定将条目放置在哪个哈希桶中。它根据 key 对象的 hashCode() 来决定。现在,hashCode() 可以是任何整数。所以它首先对哈希码执行此操作:

(h = key.hashCode()) ^ (h >>> 16)

现在,在本例中您的 key 属于 Character 类型。 CharacterhashCode 是字符本身的值。 Java char 是 16 位宽。因此向右移动 16 位将得到零。将其与零进行异或即可得到原始值 - char 值!

您选择的值是连续的。这意味着它们将恰好存储在哈希表桶中索引为 i、i+1、i+2...

这也恰好是 toString 所基于的条目集迭代器遍历该表的顺序:它连续地遍历该表。因此,只要不发生冲突,对于恰好连续的 Character 键,您就会看到结果“已排序”。

关于java - 尽管 HashMap 是一个无序集合,但为什么它会自动对字符类型键进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33965702/

相关文章:

Java : HashSet vs. 哈希表

java - 使用 Java 8 Stream API 缩减 Map

java - Logback-Slf4j 从 IDe 运行时将日志消息写入文件,但不是作为 jar

java - 从弹出窗口更新主窗口的值

java - FirebaseUI 自定义布局不显示

java - JDK 8 - "The type java.util.Map$Entry cannot be resolved"

java - 为什么我的方法会抛出 NoSuchMethodError?

java - 递归回溯二维数组(水可以从 map 上掉下来吗)

java - 如何从 HashMap 中仅打印前 10 个单词及其出现频率?

java - 什么时候包含什么?