Map的参数化类型键

Ash*_*tti 4 java generics raw-types type-safety

我正在学习Java,目前正在阅读Joshua Bloch的Effective Java.

在第29项中,他讨论了Map的参数化类型键,以创建类型安全的异构映射.这是代码:

class Favorites {
    private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();

    public <T> void putFavorite(Class<T> type, T instance) {
        if (type == null)
            throw new NullPointerException("Type is null");
        favorites.put(type, instance);
    }

    public <T> T getFavorite(Class<T> type) {
        return type.cast(favorites.get(type));
    }
}
Run Code Online (Sandbox Code Playgroud)

他接着说

恶意客户端很容易破坏收藏夹实例的类型安全性,只需使用原始形式的Class对象即可.但是生成的客户端代码在编译时会生成未经检查的警告.

我知道Class<T>会被删除到Class.但我不确定恶意客户端如何在编译时破坏类型安全性.我尝试了各种方法,但我总是遇到编译器错误,正如我所料.

有人可以告诉我Joshua Bloch在上面引用的内容中究竟是什么意思吗?

Boh*_*ian 10

原始类型是没有通用信息的类型.以下是如何打败方法的类型安全性:

Favorites favorites = new Favorites();
favorites.putFavorite((Class)Integer.class, "foo"); // no compile error
Run Code Online (Sandbox Code Playgroud)

而这不会编译:

favorites.putFavorite(Integer.class, "foo"); // compile error
Run Code Online (Sandbox Code Playgroud)

因为参数的类型是Class(而不是Class<T>),T所以无法确定通用方法参数,并且为该调用关闭类型推断.就好像调用代码的代码是pre-generics,java向后兼容(通过忽略泛型).

这是你如何防范这个问题:

public <T> void putFavorite(Class<T> type, T instance) {
    if (type == null)
        throw new NullPointerException("Type is null");
    if (!type.isInstance(instance)) // add check for instance type
        throw new IllegalArgumentException("Class/instance mismatch");
    favorites.put(type, instance);
}
Run Code Online (Sandbox Code Playgroud)

或者更残酷(因为你不能提供有关错误信息的信息),只需尝试演员:

public <T> void putFavorite(Class<T> type, T instance) {
    if (type == null)
        throw new NullPointerException("Type is null");
    favorites.put(type, type.cast(instance)); // will throw ClassCastException
}
Run Code Online (Sandbox Code Playgroud)

但是,当恶意代码试图造成损害时,这只会在运行时发现问题,但它仍然比在其他客户端尝试使用狡猾的实例时在使用时提起问题更好.

  • 或者,以一种不太奇怪的方式:`Class integerClass = Integer.class; favorites.putFavorite(integerClass,"foo");` (2认同)