在 Java 中键入擦除
Type erasure in Java
我必须处理嵌套集合(例如,列表的地图或地图的地图),这就是我要处理它的方式:
public static String doSomething(Map<?, ? extends Collection<?>> map) {
...
}
public static String doSomething(Map<?, ? extends Map<?, ?>> map) {
...
}
但是编译器告诉我,上面两个方法的类型擦除是一样的。我想知道为什么,因为我指定了不同的类型范围。
无法重载每个重载的形式参数类型擦除为相同原始类型的方法。
在您的代码中,两种方法在类型擦除后具有相同的签名:
public static String doSomething(Map map);
要解决您的问题,您可以只使用两个不同的方法名称,而不是重载该方法。
擦除Map<?, ? extends Collection<?>>
是Map<Object, Object>
擦除Map<?, ? extends Map<?, ?>>
也是Map<Object, Object>
要理解为什么,你需要了解Map
的擦除是如何计算的。基本上,您采用类型 (Map<K, V>
) 并将 formal 类型参数(而不是 actual 类型参数)替换为它们各自的 最小上限 类型。在这种情况下,K
和 V
的最小上限类型都是 Object
,因为它们都没有任何类型约束......在 Map
接口中。
我想我可能编造了这个词"least upper bound type"。 (抱歉)但我的意思是最具体的类型,它不是集合中允许的任何可能类型的子类型。
另一种理解擦除的方式如下。考虑这个 class:
public class Test <T> {
public set(T t):
}
现在想象一下,我们必须在不使用泛型的情况下表达它。我们将使用什么实际类型来代替 T
?在这种情况下,它将是 Object
.
事实上,当泛型类型映射到运行时类型时,正是会发生什么!
但是,基本上,您将无法创建仅在 Map
类型的类型参数化上有所不同的方法的重载。除非你具体化类型:
public class X implements Map<String, Integer> ...
public class Y implements Map<String, Double> ...
public static String doSomething(X map) {
...
}
public static String doSomething(Y map) {
...
}
...至少可以说是丑陋的。
解决方案:使用不同的方法名称,而不是尝试重载相同的名称。
我必须处理嵌套集合(例如,列表的地图或地图的地图),这就是我要处理它的方式:
public static String doSomething(Map<?, ? extends Collection<?>> map) {
...
}
public static String doSomething(Map<?, ? extends Map<?, ?>> map) {
...
}
但是编译器告诉我,上面两个方法的类型擦除是一样的。我想知道为什么,因为我指定了不同的类型范围。
无法重载每个重载的形式参数类型擦除为相同原始类型的方法。
在您的代码中,两种方法在类型擦除后具有相同的签名:
public static String doSomething(Map map);
要解决您的问题,您可以只使用两个不同的方法名称,而不是重载该方法。
擦除Map<?, ? extends Collection<?>>
是Map<Object, Object>
擦除Map<?, ? extends Map<?, ?>>
也是Map<Object, Object>
要理解为什么,你需要了解Map
的擦除是如何计算的。基本上,您采用类型 (Map<K, V>
) 并将 formal 类型参数(而不是 actual 类型参数)替换为它们各自的 最小上限 类型。在这种情况下,K
和 V
的最小上限类型都是 Object
,因为它们都没有任何类型约束......在 Map
接口中。
我想我可能编造了这个词"least upper bound type"。 (抱歉)但我的意思是最具体的类型,它不是集合中允许的任何可能类型的子类型。
另一种理解擦除的方式如下。考虑这个 class:
public class Test <T> {
public set(T t):
}
现在想象一下,我们必须在不使用泛型的情况下表达它。我们将使用什么实际类型来代替 T
?在这种情况下,它将是 Object
.
事实上,当泛型类型映射到运行时类型时,正是会发生什么!
但是,基本上,您将无法创建仅在 Map
类型的类型参数化上有所不同的方法的重载。除非你具体化类型:
public class X implements Map<String, Integer> ...
public class Y implements Map<String, Double> ...
public static String doSomething(X map) {
...
}
public static String doSomething(Y map) {
...
}
...至少可以说是丑陋的。
解决方案:使用不同的方法名称,而不是尝试重载相同的名称。