创build一个数组来存储Java中的genericstypes

假设我必须创build一个数组来存储整数的ArrayList,数组大小为10。

下面的代码将做到这一点:

ArrayList<Integer>[] pl2 = new ArrayList[10]; 

问题1:

在我看来,更合适的代码将是

 ArrayList<Integer>[] pl2 = new ArrayList<Integer>[10]; 

为什么这不起作用?

问题2:

下面两个都编译

  1. ArrayList<Integer>[] pl2 = new ArrayList[10];
  2. ArrayList[] pl3 = new ArrayList[10];

pl2pl3的参考声明而言,有什么区别?

问题1:

基本上这是Java语言所禁止的。 这在generics的Java语言规范中有所涉及。

当你使用

 ArrayList<Integer>[] pl2 = new ArrayList[10]; // warning 

你会得到编译器的警告,因为下面的例子将会编译(为每一行代码产生警告):

 ArrayList wrongRawArrayList = new ArrayList(); // warning wrongRawArrayList.add("string1"); // warning wrongRawArrayList.add("string2"); // warning pl2[0] = wrongRawArrayList; // warning 

但现在你的数组,应该包含Integer ArrayList ,包含完全错误的String对象的ArrayList

问题2:

正如已经回答的那样, p12声明为您提供了编译时检查的function,并且在从ArrayList获取项目时使您免于使用强制转换。

前面的例子略有修改:

 ArrayList<Integer>[] pl2 = new ArrayList[10]; // warning ArrayList<String> wrongArrayList = new ArrayList<String>(); // OK! wrongArrayList.add("string1"); // OK! wrongArrayList.add("string2"); // OK! pl2[0] = wrongArrayList; // ERROR 

现在,因为你正在使用generics,所以不能编译。 但是,如果你使用

 ArrayList[] pl2 = new ArrayList[10]; 

你会得到与第一个例子相同的结果。

通用信息只在编译时才起作用,它告诉编译器哪种types可以放入数组中,在运行时,所有的通用信息都将被删除,所以重要的是如何声明通用types。

在Java中引用Think:

说你不能创buildgenericstypes的数组是不正确的。 诚然,编译器不会让你实例化一个genericstypes的数组。 但是,它会让你创build一个这样的数组的引用。 例如:

 List<String>[] ls; 

这通过编译器没有投诉。 虽然你不能创build一个真正的数组对象,它可以保存generics,你可以创build一个非genericstypes的数组,并将其转换为:

 //: arrays/ArrayOfGenerics.java // It is possible to create arrays of generics. import java.util.*; public class ArrayOfGenerics { @SuppressWarnings("unchecked") public static void main(String[] args) { List<String>[] ls; List[] la = new List[10]; ls = (List<String>[])la; // "Unchecked" warning ls[0] = new ArrayList<String>(); // Compile-time checking produces an error: //! ls[1] = new ArrayList<Integer>(); // The problem: List<String> is a subtype of Object Object[] objects = ls; // So assignment is OK // Compiles and runs without complaint: objects[1] = new ArrayList<Integer>(); // However, if your needs are straightforward it is // possible to create an array of generics, albeit // with an "unchecked" warning: List<BerylliumSphere>[] spheres = (List<BerylliumSphere>[])new List[10]; for(int i = 0; i < spheres.length; i++) spheres[i] = new ArrayList<BerylliumSphere>(); } } 

一旦你有一个List []的引用,你可以看到你得到了一些编译时检查。 问题是数组是协变的,所以List []也是一个Object [],你可以用它来为你的数组分配一个ArrayList,在编译时和运行时都不会有错误。

如果你知道你不想上传,而且需求相对简单,那么可以创build一个generics数组,这将提供基本的编译时types检查。 但是,通用容器实际上总是比generics更好的select。

数组是协变的。 这意味着它们在运行时保留其元素的types。 Java的generics不是。 他们使用types擦除基本上掩盖正在进行的隐式转换。 理解这一点很重要。

你需要使用Array.newInstance()

此外,数组还携带有关其组件types的运行时types信息,即所含元素的types。 当元素存储在数组中时,使用关于组件types的运行时types信息,以确保不能插入“外来”元素。

更多细节请看这里

这不起作用,因为generics类不属于Reifiabletypes

关于数组创buildexpression式的JLS指出:

如果 [类types]不表示可调整types (§4.7),则是编译时错误 。 否则,[类types]可以命名任何命名引用types,甚至是抽象类types(§8.1.1.1)或接口types(§9)。

上面的规则意味着数组创buildexpression式中的元素types不能是一个参数化types,除了无界通配符以外

Reifiable Types的定义是:

由于某些types信息在编译过程中被删除,所以在运行时并不是所有的types都可用。 在运行时完全可用的types称为可重用types。

只有在以下情况之一的情况下,types才可赋予权限:

 It refers to a non-generic class or interface type declaration. It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1). It is a raw type (§4.8). It is a primitive type (§4.2). It is an array type (§10.1) whose element type is reifiable. It is a nested type where, for each type T separated by a ".", T itself is reifiable. For example, if a generic class X<T> has a generic member class Y<U>, then the type X<?>.Y<?> is reifiable because X<?> is reifiable and Y<?> is reifiable. The type X<?>.Y<Object> is not reifiable because Y<Object> is not reifiable. 

先从问题2开始,然后回到问题1:

问题2:

> ArrayList [] pl2 = new ArrayList [10]; ArrayList [] pl3 = new ArrayList [10];

就p12和p13的参考声明而言,有什么不同?

在PL2中确保比P13更好的安全性。

如果我写pl2:

 pl2[0]=new ArrayList<String>(); 

它会给我一个编译器错误,指出“不能从ArrayList<String>转换为ArrayList<Integer>

从而确保编译时的安全性。

但是,如果我写p13

 pl3[0]=new ArrayList<String>(); pl3[1]=new ArrayList<Integer>(); 

它不会抛出任何错误,开发人员将负责在从p13中提取数据时进行正确的编码和检查,以避免在运行时进行任何不安全的types转换。

问题1:

这可能是仿制药的工作方式。 在主数组初始化期间,只有在初始化索引位置的ArrayList对象时, ArrayList<Integer>[] pl2 = new ArrayList[10] ,左边的ArrayList<Integer>[] pl2将确保types安全:

 pl2[0]=new ArrayList<Integer>(); 

右侧主数组声明= new ArrayList[10]只是确保索引位置将保存ArrayListtypes的项目。 另请参阅Type Erasure中的types擦除概念以获取更多信息。

问题1。

那么这不是正确的语法。 因此,这是行不通的。

问题2。

 ArrayList<Integer>[] pl2 = new ArrayList[10]; ArrayList[] pl3 = new ArrayList[10]; 

由于pl2在编译时被定义为genericstypes<Integer>,所以编译器会知道pl2只允许有整数,如果你试图指定除Integers之外的其他东西,你将会被警告,编译将失败。

在PL3中,由于没有genericstypes,所以可以将任何types的对象分配给列表。

  ArrayList<Integer>[] pl2 = new ArrayList<Integer>[10]; 

意味着在正常情况下从ArrayList示例中检索数据时不需要执行转换

  ArrayList[] pl2 = new ArrayList[10]; pl2.put(new Integer(10)); Integer i = p12.get(0); // this is wrong Integer i = (Integer)p12.get(0); // this is true with casting 

  ArrayList<Integer>[] pl2 = new ArrayList<Integer>[10]; pl2.put(new Integer(10)); Integer i = p12.get(0); // this is true no need for casting 

generics的问题默认情况下是编译器发出的警告。

编译之后,由于types擦除,它们都变成了ArrayList[] pl2 = new ArrayList[10] ,但编译器警告你这样做不好。

generics已经被添加到Java,并且向后兼容,您可以使用generics与非generics互换。

问题1

您不能创build参数化types的数组

问题2

  ArrayList<Integer>[] pl2 = new ArrayList[10]; 

这意味着你正在告诉编译器你将要创build一个数组来存储整数列表。 您的数组列表将只包含Integer对象。 这就是generics进入的地方。generics使您的代码更加安全可靠。 如果你确定你的列表只应该包含整数对象,那么你应该总是这样做。

但是当你说

  ArrayList[] pl3 = new ArrayList[10]; 

这意味着arraylist可以存储任何对象types,如string,整数,自定义对象等

看来你不能创build一个具有genericstypes的ArrayList的数组 ,根据堆栈溢出问题的答案创build一个ArrayList元素的数组

据我所知,在Java中没有generics这样的东西。 就types而言, ArrayList<Integer> and ArrayList是相同的东西。

Java使用types擦除的generics。 这意味着所有关于generics的types信息都会在编译时被删除。 所以ArrayList<Integer>成为ArrayList。

所以这只是一个编译技巧。 我猜测,为了避免程序员可能做的任何混乱或错误,他们允许ArrayList<Integer>[]像这样被实例化: new ArrayList[10]

所以一个ArrayList<Integer>[]和一个ArrayList[]是相同的东西,因为括号中的信息在编译时被擦除。