java - 如果我们应用类型删除,哪些重载方法将在运行时被调用,为什么?

标签 java generics overloading type-erasure

假设我们有下面的泛型类

public class SomeType<T> {
    public <E> void test(Collection<E> collection){
        System.out.println("1st method");

        for (E e : collection){
            System.out.println(e);
        }
    }

    public void test(List<Integer> integerList){
        System.out.println("2nd method");

        for (Integer integer : integerList){
            System.out.println(integer);
        }
    }

}

现在在 main 方法中我们有以下代码片段

SomeType someType = new SomeType();
List<String> list = Arrays.asList("value");
someType.test(list);

作为执行 someType.test(list) 的结果我们将在我们的控制台中获得“第二种方法”以及 java.lang.ClassCastException .据我了解,为什么第二个test的原因正在执行的方法是我们不对 SomeType 使用泛型.因此,编译器会立即从类中删除所有泛型信息(即 <T><E> )。在做了那一秒之后 test方法将有 List integerList作为参数,当然还有 ListList 更匹配比 Collection .

现在考虑在 main 方法中我们有以下代码片段

SomeType<?> someType = new SomeType<>();
List<String> list = Arrays.asList("value");
someType.test(list);

在这种情况下,我们将在控制台中获得“第一种方法”。这意味着第一个测试方法正在执行。问题是为什么?

根据我对运行时的理解,由于类型删除,我们从来没有任何泛型信息。那么,为什么第二个test方法无法执行。我第二test方法应(在运行时)采用以下形式 public void test(List<Integer> integerList){...}不是吗?

最佳答案

适用的方法匹配之前类型删除(see JSL 15.12.2.3) . (删除意味着运行时类型没有参数化,但是方法是在编译时选择的,当类型参数可用时)

list 的类型是List<String> ,因此:

  • test(Collection<E>) 适用,因为List<Integer>Collection<E> 兼容, 其中EInteger (形式上,约束公式 List<Integer> → Collection<E> [E:=Integer] 简化为 true ,因为 List<Integer>Collection<Integer> 的子类型)。

  • test(List<String>)不适用,因为 List<String>List<Integer> 不兼容(形式上,约束公式 List<String>List<Integer> 减少为 false 因为 String 不是 Integer 的父类(super class)型)。

详细信息解释隐藏在JSL 18.5.1中.

对于 test(Collection<E>) :

Let θ be the substitution [E:=Integer]

[...]

A set of constraint formulas, C, is constructed as follows: let F1, ..., Fn be the formal parameter types of m, and let e1, ..., ek be the actual argument expressions of the invocation.

在这种情况下,我们有 F1 = Collection<E>e1 = List<Integer>

Then: [the set of constraint formulas] includes ‹ei → Fi θ›

在这种情况下,我们有 List<Integer> → Collection<E> [E:=Integer] (其中 → 表示在推断类型变量 E 后 e1 与 F1 兼容)

对于 test(List<String>) , 没有替换(因为没有推理变量)并且约束只是 List<String>List<Integer> .

关于java - 如果我们应用类型删除,哪些重载方法将在运行时被调用,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34306094/

相关文章:

java - 使用泛型子类型覆盖继承接口(interface)中的方法

ArrayList 数据类型的 Java 重载

java - 将 ByteBuffer 与 FloatBuffer 结合起来

java - 如何查看被截断的完整 ant 构建错误

Java SQL 插入多个变量

c# - ArrayList 与 C# 中的 List<>

java - JPanel如何添加ToolTipText

java - 在 Java 中初始化通用变量?

c11 _Generic 添加类型

python - python 中的重载 - pandas