在Java中创建泛型列表数组时出错
第一个代码:在Java中创建泛型列表数组时出错,java,arrays,generics,syntax,Java,Arrays,Generics,Syntax,第一个代码: List<Integer>[] array = (List<Integer>[]) new Object[size]; E[] array = (E[]) new Object[size]; List<Integer>[] array = (List<Integer>[]) new List[size]; 但是我发现下面的代码是有效的 第三个代码: List<Integer>[] array = (List<
List<Integer>[] array = (List<Integer>[]) new Object[size];
E[] array = (E[]) new Object[size];
List<Integer>[] array = (List<Integer>[]) new List[size];
但是我发现下面的代码是有效的
第三个代码:
List<Integer>[] array = (List<Integer>[]) new Object[size];
E[] array = (E[]) new Object[size];
List<Integer>[] array = (List<Integer>[]) new List[size];
List[]数组=(List[])新列表[size];
我的问题是:
public class Test<E>{
E[] array;
public Test(){
array = (E[]) new Object[10];
}
public E set(E x){
array[0] = x;
System.out.println(array[0]);
return array[0];
}
public static void main(String[] args){
Test<List<Integer>> test = new Test<>();
List<Integer> list = new ArrayList<>();
list.add(1);
test.set(list);
}
}
公共类测试{
E[]阵列;
公开考试(){
数组=(E[])新对象[10];
}
公共E集(ex){
数组[0]=x;
System.out.println(数组[0]);
返回数组[0];
}
公共静态void main(字符串[]args){
测试=新测试();
列表=新的ArrayList();
增加第(1)款;
测试集(列表);
}
}
List<Integer>[] array = (List<Integer>[]) new Object[size];
E[] array = (E[]) new Object[size];
List<Integer>[] array = (List<Integer>[]) new List[size];
List[]数组=新列表[大小]代码>第一个代码
Java中的泛型有点奇怪。出于各种原因,例如向后兼容性,泛型基本上被编译器删除,并且(大多数情况下)不会出现在已编译的代码()中。相反,它将使用()来确定应该在代码中使用什么类型。对于一个基本的未绑定泛型;此类型将是对象
。因此,假设E
上没有绑定,编译器将第二个代码更改为:
Object[] array = (Object[]) new Object[size];
因此,由于两个数组在擦除后具有完全相同的类型,因此在运行时没有问题,并且强制转换基本上是冗余的
值得注意的是,只有E
是无界的,这一点才有效。例如,在运行时使用ClassCastException
:
public static <E extends Number> void genericMethod() {
final int size = 5;
E[] e = (E[]) new Object[size];
}
在处理代码时,记住擦除是很重要的。否则,您可能会遇到代码行为与预期不同的情况。例如,以下代码:
这没有问题,因为ArrayList
是List
的子类型
第四个代码
List[]array=newarrayList[size];
以上内容将无法编译。以下情况明确禁止使用具有泛型类型参数的类型创建数组:
如果正在初始化的数组的组件类型不可重新定义,则为编译时错误(§4.7)
具有非无界通配符(?
)的泛型参数的类型不满足以下条件:
当且仅当下列条件之一成立时,类型才可重新定义:
- 它引用非泛型类或接口类型声明
- 它是一种参数化类型,其中所有类型参数都是无界通配符(§4.5.1)
- 这是一种原始类型(§4.8)
- 它是一种基本类型(§4.2)
- 它是一种数组类型(§10.1),其元素类型是可重新定义的
- 它是一个嵌套类型,其中,对于每个由“.”分隔的类型T,T本身是可重新定义的
虽然我没有时间深入研究JLS
,但我可以暗示您需要进一步研究(尽管每次我这样做,都不是一次非常愉快的旅行)
这些不是可证明的不同类型;编译器无法判断这是否必须失败。这里还有一点,编译器不会以任何形式或形状强制转换为泛型类型,您可以轻松地执行类似的操作(仍然可以编译):
第二点是类型擦除(同样JLS
has)
编译代码后,E[]
在运行时是Object[]
(除非有一个边界,但这里不是这种情况),很明显,您可以将任何您想要的东西放入其中。Java中数组和泛型之间的交互是混乱的,因为它们是基于不同的假设构建的。Java数组有运行时类型检查,泛型只有编译时类型检查
Java通过结合编译时和运行时检查来实现类型安全。强制转换绕过了大多数编译时检查,但仍有运行时检查。数组的类型兼容性规则与其包含的元素类型基本相同。因此:
Object[] a = new String[size]; //ok, but be aware of the potential for an ArrayStoreException
String[] a = new Object[size]; //compile error
String[] a = (String[]) new Object[size]; //runtime error
当Sun决定向Java添加泛型时,他们决定使用泛型的代码应该在现有JVM上工作,因此他们决定通过擦除实现泛型。泛型类型仅在编译时存在,在运行时它们被普通类型替换
所以在擦除之前,我们有以下陈述
List<Integer>[] array = (List<Integer>[]) new Object[size];
E[] array = (E[]) new Object[size];
List<Integer>[] array = (List<Integer>[]) new List[size];
E[]数组=(E[])新对象[size]应谨慎使用代码>结构,这违反了Java的正常类型模型,如果数组返回到非泛型上下文,将导致混乱的ClassCastException。不幸的是,通常没有更好的选择,因为类型擦除,泛型类型无法找到它的元素类型并构造正确类型的数组。请包含编译器错误。此外,混合泛型和数组几乎总是一件麻烦事,因为数组是协变的并保留,而泛型是不变的并被删除。在向下转换时,你必须非常小心。不是每个对象都是一个列表,但每个列表都是一个对象。检查一下,@farhanfarooki我已经更新了我的问题。如何解释我的问题1?List[]数组=(List[])新列表[size]代码>这样行吗?你确定?这甚至不可能compile@Eugene我说第一个代码错了,但第二个代码正确。您可以将问题1下面的代码粘贴到ide中。它工作得很好。+1因为您提到了类型擦除+有界类型擦除。虽然演员阵容失败与否的原因仍在JLS中,但名称不同。。。
List<Integer>[] array = (List<Integer>[]) new Object[size];
array = (E[]) new Object[10];
String s[][][] = new String[1][2][3];
array = (E[]) s; // this will compile, but makes little sense
Object[] a = new String[size]; //ok, but be aware of the potential for an ArrayStoreException
String[] a = new Object[size]; //compile error
String[] a = (String[]) new Object[size]; //runtime error
List<Integer>[] array = (List<Integer>[]) new Object[size];
E[] array = (E[]) new Object[size];
List<Integer>[] array = (List<Integer>[]) new List[size];
List[] array = (List[]) new Object[size]; //run time error.
Object[] array = (Object[]) new Object[size]; //no error.
List[] array = (List[]) new List[size]; //no error.