java - 使用集合进行类型删除

标签 java generics

我无法理解涉及集合时类型删除的确切工作原理。

如果我们看一下这段代码:

static void print(Object o){
   System.out.println("Object");
}
static void print(String s){
   System.out.println("String");
}
static void print(Integer i){
   System.out.println("Integer");
}
static <T> void printWithClass (T t)
   print(t);
}
public static void main(String[] args){
   printWithClass("abc") //String is printed, because T turns to Object after type erasure.
}

这个例子我理解,但是这个我不能理解:

class Printer<T>{
    void print(Collection<?> c){
        System.out.println("1");
    }
    void print(List<Number> l){
        System.out.println("2");
    }
    void printWithClass(List<T> ts){
        print(ts);
    }
    
}

public class Main
{
 public static void main(String[] args){
        Printer<Integer> printer=new Printer<>();
        printer.printWithClass(new ArrayList< Integer>()); //1 is printed
    }  
}

我无法理解为什么精确地打印 1。在我看来,类型删除后的代码将如下所示:

        void print(Collection c){
            System.out.println("1");
        }
        void print(List l){
            System.out.println("2");
        }
        void printWithClass(List ts){
            print(ts);
        }

但这是错误的。

在我看来,类型删除有两个阶段——一个阶段将 T 转换为 Object,另一个阶段是 List<...>将变成List .

我认为这是不正确的,有人可以解释一下这里发生了什么吗?

编辑:我想出了这个猜测:编译器记得最初的参数是 List<Number>因为这对于单独编译很重要。但是,它不记得最初进入 printWithClass 的内容是什么。是List<Number>同样,它只能知道它是 List

最佳答案

请记住,方法重载是在编译时解决的(与将在运行时解决的方法覆盖相反)。

这意味着必须在 printWithClass 时决定调用哪个特定方法签名。已编译。这也意味着此时不会进行类型删除(因为删除是运行时的属性,所以编译器仍然关心所有类型参数)。

在此方法中:

void printWithClass(List<T> ts){
    print(ts);
}

T完全无界(即它可以是任何可能的引用类型),只有一种可能的 print调用的方法,即采用 Collection<?> 的方法,因为我们无法知道TNumber .

作为旁注,自从 List<Integer> 不是 List<Number> ,即使这些规则不同,您的 main方法无法导致其他 print被调用的方法。

关于java - 使用集合进行类型删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66629648/

相关文章:

java - 让 Android Http BufferedReader 更高效?

java - 避免在JDK升级后实现新的接口(interface)方法

java - Android Studio - 让 Activity 等待加载 UI

c# - 使用函数技术在 F# 中使用泛型重新实现 C# 继承

java - 回文字符串 VarArgs - Java(没有数组,只有 VarArgs)

c# - 如何使用字典引用动态类型?

java - 使用 super 关键字迭代通用列表

c# - 如何使用 System.Reflection.Emit 从 T 创建派生类型

c# - 让工厂类使用泛型来实例化对象是个好主意吗?

java - Android drawSelectorOnTop 与 GridView