10

我正在尝试创建一个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();
4

1 回答 1

16

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

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>,因此它是所有Class实例的公共超类型。因此,类型参数将被Class<?>自动推断为。它会工作得很好。

于 2013-10-02T18:36:41.767 回答