创建使用Class <! - ? - >作为键的ImmutableMap的问题

时间:2013-10-02 18:19:48

标签: java class generics reflection guava

我正在尝试创建一个将类映射到字符串的ImmutableMap(注意:这当然只是一个例子!)。但是,像是

ImmutableMap<Class<?>, String> map = ImmutableMap.of( 
    Integer.class, "Integer", 
    Date.class, "Date" 
);

给我以下错误

Type mismatch: cannot convert from ImmutableMap<Class<? extends Object&Comparable<?>&Serializable>,String> to ImmutableMap<Class<?>,String>

奇怪的是,如果我向Class<?>添加任何(!)键的转换,它就会起作用,即

ImmutableMap<Class<?>, String> map = ImmutableMap.of(
    Integer.class, "Integer",
    Date.class, "Date",
    (Class<?>) String.class, "String",
    long.class, "Long"
);

工作得很好。我有点对这种行为感到困惑:首先,为什么没有演员阵容就行不通?所有这些都是类,它实际上没有比Class<?>更通用,所以为什么它不起作用?其次,为什么任何一个键上的强制转换都能使它工作?

(旁注:如果你想知道为什么我甚至想做这样的事情 - 是的,这是因为反思......)

编辑:我其实只知道这会有效,但我还是想了解上述行为

ImmutableMap<Class<?>, String> map = ImmutableMap.<Class<?>, String>builder()
    .put( Integer.class, "Integer" )
    .put( Date.class, "Date" )
    .build();

1 个答案:

答案 0 :(得分:15)

当您传递不一致的方法参数时,这就是编译器推断类型参数的方式。 如果您注意到,ImmutableMap.of(K, V, K, V)方法对KDate使用相同的类型参数Integer。有人会认为这会失败,因为我们传递的是不一致的方法参数,这意味着我们为相同的类型参数K传递了不同的类型。但令人惊讶的是它没有。

Class<Date>Class<Integer>可以转换为以下所有内容:

  • Class<? extends Object>
  • Class<? extends Serializable>
  • Class<? extends Comparable<?>>

因此,类型K被推断为所有的混合:

K := Class<? extends Object&Serializable&Comparable<?>>

这个方法的返回值实际上是:

ImmutableMap<Class<? extends Object&Serializable&Comparable<?>>, String>

当然,您无法将其直接分配给ImmutableMap<Class<?>, String>,因为它们是不兼容的类型。另请注意,您无法如上所述明确声明地图,因为您无法为通配符提供多个边界。它只是编译器推断类型的方式。

对于这些情况,编译器无法正确推断出你需要的类型参数,你可以传递 显式类型参数 ,同时方法调用,这就是你的意思在你的最后一次尝试中做到了:

ImmutableMap<Class<?>, String> map = ImmutableMap.<Class<?>, String>of( 
    Integer.class, "Integer", 
    Date.class, "Date" 
);

现在这将起作用,因为编译器从显式类型参数知道返回值的类型为ImmutableMap<Class<?>, String>

  

奇怪的是,如果我向Class<?>添加任意(!)键的演员

,它确实有效

只要您将任何元素输出到Class<?>,因为Class<?>表示所有Class<T>的所有实例的家族,因此它是所有{的常见超类型{1}}个实例。因此,type参数将自动推断为Class。它会工作正常。