Java 尝试打印原始类型集的内容时的 TreeSet 行为

Java's TreeSet behavior when trying to println the content of a raw type set

当我尝试 运行 下面的代码时,出现 运行 时间错误:java.lang.Integer cannot be cast to java.lang.String

Set vals = new TreeSet();
vals.add(1);
vals.add("two");
System.out.println(vals); 

我尝试用HashSet、HashLinkedSet、ArrayList等替换,都运行打印了答案。看来只有TreeSet不行了!

我的假设是,发生这种情况是因为 TreeSet 在 运行 时间对对象进行了比较,这会失败。

但是,我也知道其他类型的集合(例如 HashSet)需要进行相同的比较(但也许在 HashSet 中,比较发生在两个散列值之间?并且没有转换失败?)

为什么会这样?

TreeSet 以排序顺序存储值,因此,它需要比较两个元素的顺序,而不仅仅是相等性。它在内部使用 TreeMap 来存储值,并且在将值插入 TreeMap 时,地图会比较键以进行排序。从堆栈跟踪

可以明显看出,在比较期间发生错误
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at java.lang.String.compareTo(Unknown Source)
    at java.util.TreeMap.put(Unknown Source)
    at java.util.TreeSet.add(Unknown Source)
    at Test.main(Test.java:10)

String class 的 compareTo 方法的签名如下所示:

 public int compareTo(String anotherString)

因此,当在您的代码中使用 int 参数调用此方法时,该集合包含一个 int 值,运行时错误发生在 Class 转换

同理,如果先把String加入set,再加入Integer,如下图:

    Set vals = new TreeSet();
    vals.add("two");
    vals.add(1);
    System.out.println(vals); 

您会看到 Integer 的异常 class

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at java.lang.Integer.compareTo(Unknown Source)
    at java.util.TreeMap.put(Unknown Source)
    at java.util.TreeSet.add(Unknown Source)
    at Test.main(Test.java:10)

HashSet 的情况下,不会发生此问题,因为正在比较元素是否相等。

String class 的 equals 方法的签名如下所示:

public boolean equals(Object anObject)

这里可以看到,入参是java.lang.Object,给这个函数传一个整数就可以了,没有任何错误。该实现在内部使用 instanceof 运算符来检查类型兼容性,并避免使用 ClassCastException

你可以说是 compareToequals 的实现方式不同导致了这个错误。