首页 > 解决方案 > 阅读 Core Java 第 11 版时关于 **Type Erasure 机制** 的问题

问题描述

这是作者在书中提供的关于泛型编程的代码示例:

public class Pair<T>
{
  private T first;
  private T second;
  public Pair() { first = null; second = null; }
  public Pair(T first, T second) { this.first = first; this.second = second; }
  public T getFirst() { return first; }
  public T getSecond() { return second; }
  public void setFirst(T newValue) { first = newValue; }public void setSecond(T newValue) { 
  second = newValue; }
}

然后作者介绍了类型擦除机制

无论何时定义泛型类型,都会自动提供相应的原始类型。原始类型的名称只是泛型类型的名称,类型参数已删除。类型变量被删除并替换为它们的边界类型(或例如,对象的原始类型用于无边界变量)。

您的程序可能包含不同类型的擦除将它们全部转换为原始 Pair ,例如 Pair<String>or Pair<LocalDate>,但擦除将它们全部转换为原始 Pair 类型。

所以对于 的情况class Pair<T>,擦除后它变成下面的raw Pair 类型

public class Pair
{
  private Object first;private Object second;
  public Pair(Object first, Object second)
  {
  this.first = first;
  this.second = second;
  }
  public Object getFirst() { return first; }
  public Object getSecond() { return second; }
  public void setFirst(Object newValue) { first = newValue; }
  public void setSecond(Object newValue) { second = newValue; }
}

所以如果我们运行代码,打印 TURE

Pair<Integer> p = new Pair<Integer>(1, 2);
Pair<String> s = new Pair<String>("a", "b");
System.out.println(p.getClass()==s.getClass());

问题来了,当我创建一个Pair<T>类型错误的实例时,例如:

 Pair<String> s = new Pair<String>("a", 1);

编译器可以找出问题并打印此消息:</p>

pair1/PairTest1.java:12:错误:不兼容的类型:int 不能转换为 String Pair s = new Pair("a", 1);

sice<T>被擦除为 Object 并且构造函数变为:

public Pair(Object first, Object second)
  {
  this.first = first;
  this.second = second;
  }

并且参数类型变成了对象,所以:

编译器如何确定类型错误?类型擦除何时 发生?

标签: javatypescastingtype-conversionjvm

解决方案


类型擦除发生在编译器生成字节码时,但编译器在验证源代码时知道泛型类型。那时还没有删除任何内容。

然而,编译器知道即使在验证期间也会发生擦除。例如,如果您重载这样的方法:

void doStuff(List<Integer> intList) {}
void doStuff(List<String> stringList) {}

编译器知道两者都将void doStuff(List xxx) {}在擦除之后,并且您不能有两个具有相同签名的方法1,因此即使类型擦除尚未发生,验证步骤也会为此生成错误消息。

1) 参数名称不是签名的一部分


推荐阅读