通过集合进行类型擦除

问题描述 投票:0回答:1

我无法理解当涉及集合时类型擦除到底是如何工作的。

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

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"); // Object 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

java generics
1个回答
2
投票

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

这意味着必须在编译 printWithClass 时决定调用哪个特定方法签名

。这也意味着此时不会进行类型擦除(因为擦除是运行时的属性,所以编译器仍然关心所有类型参数)。

在此方法中:

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

T

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

顺便说一句,由于

List<Integer>

 
不是 List<Number>
,即使这些规则不同,您的 
main
 方法也不会导致调用其他 
print
 方法。

© www.soinside.com 2019 - 2024. All rights reserved.