java - 为什么 Map#put 指定@throws ClassCastException?

标签 java generics javac

考虑 put 的规范java.util.Map 的方法界面。

它说:

@throws ClassCastException if the class of the specified key or value 
        prevents it from being stored in this map

Map 是具有两个类型参数 的通用接口(interface):KV 用于键对象和值对象分别。 put 方法签名是:

V put(K key, V value);

在什么情况下调用此方法可能会在运行时导致 ClassCastException

我认为如果存在一些泛型和原始类型的混合,那么在忽略编译器警告的同时,这可能会发生。因此,在重读 Effective Java 2 之后,我根据 unsafeAdd 示例(项目 #23,第 112 页)对以下内容进行了建模:

public class MapClassCastException {
    public static void main(String[] args) {
        Map<Integer, String> m = new HashMap<>();
        unsafePut(m);
        System.out.println(m.get(1));
    }

    private static void unsafePut(Map m) { // beware: Raw Type
        m.put("blow", "up");
        m.put(new int[]{2, 4}, "xxx");
    }
}

但这段代码不会在运行时因 ClassCastException 而失败,而是打印 null。 (当然,我忽略编译器警告只是为了更好地理解它)。

有人可以演示 Map#put 如何在运行时抛出 ClassCastException 吗? (我在 JDK 1.6、1.7 和 1.8 上尝试过,它们产生了相同的结果)。

最佳答案

Map 是一个接口(interface),它实质上为该接口(interface)的所有实现定义了一个契约。 Map.put 的文档告诉您此方法可能会抛出 ClassCastException。这并不要求所有实现都抛出它。

如果您查看 documentation for HashMap.put ,您会注意到它根本没有提到 ClassCastException。如评论中所述,TreeMap.put确实会抛出 ClassCastException,因为它需要能够准确地比较键。

如果您想实现自己的 java.util.Map,如果您想限制键或值的类型,则可以抛出 ClassCastException,即使如果您碰巧使用原始 Map 类型,则接口(interface)上的泛型无法强制执行。

我认为这只是 Collections API 的实现者所说的要小心。

关于java - 为什么 Map#put 指定@throws ClassCastException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42603687/

相关文章:

c# - 在简单注入(inject)器中注册具有构造函数参数的泛型类型

java - 如何强制 Java 8 wsimport 命令行生成 1.6 目标兼容代码

java - 哪个布局管理器适合我的设计?

java - SQL查询没有返回结果怎么办?

c# - 为什么我的方法需要错误的返回类型?

java - Java-8 中的方法引用和泛型

java - OpenJDK 14.0.1 给出 "the switch expression does not cover all possible input values"

Javac版本没有更新

java - 如何获取带标签的pdf中标签的页码

java - 将 C++ 项目导出到 Android - JNI/JavaCPP/Visualgdb