我无法理解涉及集合时类型删除的确切工作原理。
如果我们看一下这段代码:
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<?>
的方法,因为我们无法知道T
是 Number
.
作为旁注,自从 List<Integer>
不是 List<Number>
,即使这些规则不同,您的 main
方法无法导致其他 print
被调用的方法。
关于java - 使用集合进行类型删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66629648/