Java:通用擦除的工作原理
场景A.java--------------擦除后------->M.class 场景B.java--------------擦除后------->M.class 那么为什么A是非法的,而B是合法的,因为它们在擦除后具有几乎相同的M 擦除前的场景A: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
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,非常感谢!!我现在更清楚了。