Java:通用擦除的工作原理

Java:通用擦除的工作原理,java,arrays,generics,type-erasure,Java,Arrays,Generics,Type Erasure,场景A.java--------------擦除后------->M.class 场景B.java--------------擦除后------->M.class 那么为什么A是非法的,而B是合法的,因为它们在擦除后具有几乎相同的M 擦除前的场景A: class ArrayList<V> { private V[] backingArray; public ArrayList() { backingArray = new V[DEFAU

场景A.java--------------擦除后------->M.class

场景B.java--------------擦除后------->M.class

那么为什么A是非法的,而B是合法的,因为它们在擦除后具有几乎相同的M

擦除前的场景A:

 class ArrayList<V> {
 private V[] backingArray;
         public ArrayList() {
             backingArray = new V[DEFAULT_SIZE]; // illegal
           }
 }
class ArrayList<V> {
  private V[] backingArray;
  public ArrayList() {
    backingArray = (V[]) new Object[DEFAULT_SIZE]; 
  }
}
类数组列表{
私人V[]后台阵列;
公共数组列表(){
backingArray=new V[默认大小];//非法
}
}
擦除后的场景A:

 class ArrayList<V> {   
   private Object[] backingArray;   
      public ArrayList() {
      backingArray = new Object[DEFAULT_SIZE]; // this is not useful   
   } 
}
class ArrayList<V> {
  private Object[] backingArray;
  public ArrayList() {
    backingArray = (Object[]) new Object[DEFAULT_SIZE]; 
  }
}
类数组列表{
私有对象[]备份阵列;
公共数组列表(){
backingArray=新对象[默认大小];//这没有用
} 
}
实际上,对象[默认大小]很有用~ 擦除前的场景B:

 class ArrayList<V> {
 private V[] backingArray;
         public ArrayList() {
             backingArray = new V[DEFAULT_SIZE]; // illegal
           }
 }
class ArrayList<V> {
  private V[] backingArray;
  public ArrayList() {
    backingArray = (V[]) new Object[DEFAULT_SIZE]; 
  }
}
类数组列表{
私人V[]后台阵列;
公共数组列表(){
backingArray=(V[])新对象[默认大小];
}
}
擦除后的场景B:

 class ArrayList<V> {   
   private Object[] backingArray;   
      public ArrayList() {
      backingArray = new Object[DEFAULT_SIZE]; // this is not useful   
   } 
}
class ArrayList<V> {
  private Object[] backingArray;
  public ArrayList() {
    backingArray = (Object[]) new Object[DEFAULT_SIZE]; 
  }
}
类数组列表{
私有对象[]备份阵列;
公共数组列表(){
backingArray=(对象[])新对象[默认大小];
}
}

场景A非法的原因是Java的协变数组不是通过擦除实现的。这:

Object[] foo = new String[4];
foo[0] = new Object();
将在运行时引发,因为
foo
引用的数组实例知道它是
字符串[]
(即使它是通过变量
foo
引用的,该变量具有编译时类型
对象[]
)。因此:

new V[4]

是非法的,因为运行时不知道要创建什么类型的数组实例。

场景A非法的原因是Java的协变数组不是通过擦除实现的。这:

Object[] foo = new String[4];
foo[0] = new Object();
将在运行时引发,因为
foo
引用的数组实例知道它是
字符串[]
(即使它是通过变量
foo
引用的,该变量具有编译时类型
对象[]
)。因此:

new V[4]

是非法的,因为运行时不知道要创建什么类型的数组实例。

那么您的意思是擦除后的代码场景A是错误的?因为
backingArray=newv[默认大小]不会变成
backingArray=新对象[默认大小]新对象[默认大小]
,也不是其他任何东西。这就像
new V()
不能成为
new Object()
一样。非常感谢,还有一个问题,您认为如果编译器将Scenario-A-before编译成Scenario-A-after会好吗?我认为,如果编译器只转换V->Object,则不会有什么区别。如果
V
String
,那么@ruakh给出的示例可能会在某些条件下导致
ArrayStoreException
。但基本上,数组和泛型在一起玩得很糟糕。哦~@LouisWasserman和@ruakh,非常感谢!!我现在更清楚了。你是说擦除后的代码场景A是错误的?因为
backingArray=newv[默认大小]不会变成
backingArray=新对象[默认大小]新对象[默认大小]
,也不是其他任何东西。这就像
new V()
不能成为
new Object()
一样。非常感谢,还有一个问题,您认为如果编译器将Scenario-A-before编译成Scenario-A-after会好吗?我认为,如果编译器只转换V->Object,则不会有什么区别。如果
V
String
,那么@ruakh给出的示例可能会在某些条件下导致
ArrayStoreException
。但基本上,数组和泛型在一起玩得很糟糕。哦~@LouisWasserman和@ruakh,非常感谢!!我现在更清楚了。