以Class <?>为关键创建ImmutableMap的问题

Ing*_*ürk 10 java generics reflection class guava

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

ImmutableMap<Class<?>, String> map = ImmutableMap.of( 
    Integer.class, "Integer", 
    Date.class, "Date" 
);
Run Code Online (Sandbox Code Playgroud)

给我以下错误

Type mismatch: cannot convert from ImmutableMap<Class<? extends Object&Comparable<?>&Serializable>,String> to ImmutableMap<Class<?>,String>
Run Code Online (Sandbox Code Playgroud)

奇怪的是,如果我Class<?>向任何(!)键添加一个强制转换,它确实有效

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

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

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

编辑:我实际上只是发现这会起作用,但我仍然想了解上述行为

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

Roh*_*ain 15

这是编译器在传递不一致的方法参数时推断类型参数的方式.如果您发现,该ImmutableMap.of(K, V, K, V)方法使用相同类型的参数,K两个DateInteger.有人会认为这会失败,因为我们传递的是不一致的方法参数,意味着我们为同一个类型参数传递不同的类型K.但令人惊讶的是它没有.

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

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

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

K := Class<? extends Object&Serializable&Comparable<?>>
Run Code Online (Sandbox Code Playgroud)

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

ImmutableMap<Class<? extends Object&Serializable&Comparable<?>>, String>
Run Code Online (Sandbox Code Playgroud)

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

对于这些情况,编译器无法根据需要正确推断类型参数,您可以在方法调用时传递显式类型参数,这是您在上次尝试时所做的:

ImmutableMap<Class<?>, String> map = ImmutableMap.<Class<?>, String>of( 
    Integer.class, "Integer", 
    Date.class, "Date" 
);
Run Code Online (Sandbox Code Playgroud)

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

奇怪的是,如果我Class<?>向任何(!)键添加一个强制转换,它确实有效

只要你输入任何元素Class<?>,因为它Class<?>表示所有实例的所有实例Class<T>,因此它是所有Class实例的常见超类型.因此,类型参数将Class<?>自动推断.它会工作正常.