Java 中的 Object TreeMap 与 Object HashMap

问题描述

public class test {
    public static void main(String[] args) {
        Map<Object,Object> m = new TreeMap();
        m.put("1",new ArrayList());
        m.put(1,new Object());
        m.put(1.0,"Hello");
        System.out.println(m);
    }
}

代码返回以下错误

Exception in thread "main" java.lang.classCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
    at java.base/java.lang.Integer.compareto(Integer.java:64)
    at java.base/java.util.TreeMap.put(TreeMap.java:566)
    at test.main(test.java:8)

但这不会发生在 HashMap 并且编译成功。我想知道这怎么可能?

解决方法

TreeMap 在内部使用比较器来构建红黑树。在这种情况下,您没有提供它,因此它会尝试比较 IntegerString,它们彼此不可比较。例如,您可以提供这样的比较器:

Map<Object,Object> m = new TreeMap<>(Comparator.comparing(String::valueOf));
m.put("1",new ArrayList<>());
m.put(1,new Object());
m.put(1.0,"Hello");
System.out.println(m);

输出:

{1=java.lang.Object@3fee733d,1.0=Hello}

根据此比较器,前两个元素是相同的,元素 new Object() 使用实现的默认 toString 方法。


HashMap 在内部使用 hashCode 方法来构建哈希表。该方法至少在 Object 类中实现,并被派生类覆盖:StringIntegerDouble。这就是为什么这段代码工作正常:

Map<Object,Object> m = new HashMap<>();
m.put("1","Hello");
System.out.println(m);

输出:

{1.0=Hello,1=[],1=java.lang.Object@5451c3a8}