创build一个数组来存储Java中的genericstypes
假设我必须创build一个数组来存储整数的ArrayList,数组大小为10。
下面的代码将做到这一点:
ArrayList<Integer>[] pl2 = new ArrayList[10];
问题1:
在我看来,更合适的代码将是
ArrayList<Integer>[] pl2 = new ArrayList<Integer>[10];
为什么这不起作用?
问题2:
下面两个都编译
-
ArrayList<Integer>[] pl2 = new ArrayList[10];
-
ArrayList[] pl3 = new ArrayList[10];
就pl2
和pl3
的参考声明而言,有什么区别?
问题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[]
是相同的东西,因为括号中的信息在编译时被擦除。