假设我必须创建一个存储ArrayList的Integers的数组,并且数组大小为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
的参考声明而言,有什么区别?
答案 0 :(得分:16)
通用信息仅在编译时很重要,它告诉编译器可以将哪种类型放入数组中,在运行时,所有通用信息都将被删除,因此重要的是如何声明泛型类型。
引自Think in Java:
说你不能创建数组是不正确的 通用类型。没错,编译器不会让你实例化一个数组 通用类型。但是,它会让你创建一个引用 这样的阵列。例如:
List<String>[] ls;
这无需投诉即可通过编译器。虽然你 你不能创建一个包含泛型的实际数组对象 创建一个非泛型类型的数组并将其强制转换:
//: 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 []的引用,你就可以看到你了 得到一些编译时检查。问题是数组是 covariant,所以List []也是一个Object [],你可以使用 这将ArrayList分配到您的数组中,没有错误 编译时间或运行时间。
如果你知道你不会去 upcast和你的需求相对简单,但是,它是可能的 创建一个泛型数组,它将提供基本的编译时 类型检查。但是,通用容器实际上总是一个 比一系列仿制药更好的选择。
答案 1 :(得分:13)
问题1:
基本上,这是Java语言禁止的。这包含在Java Language Specification for generics。
中使用时
ArrayList<Integer>[] pl2 = new ArrayList[10]; // warning
您收到编译器警告,因为以下示例将编译(为每行代码生成警告):
ArrayList wrongRawArrayList = new ArrayList(); // warning
wrongRawArrayList.add("string1"); // warning
wrongRawArrayList.add("string2"); // warning
pl2[0] = wrongRawArrayList; // warning
但是现在你应该包含ArrayList
Integer
的数组包含完全错误的ArrayList
个String
个对象。
问题2:
正如已经回答的那样,p12
的声明为您提供了编译时间检查,并使您在从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
现在,由于您使用的是泛型,因此无法编译。 但是如果你使用
ArrayList[] pl2 = new ArrayList[10];
您将获得与第一个示例中相同的结果。
答案 2 :(得分:4)
阵列是协变的。这意味着它们在运行时保留其元素的类型。 Java的泛型不是。他们使用类型擦除来基本掩盖正在进行的隐式转换。理解这一点很重要。
您需要使用Array.newInstance()
此外,数组还包含有关其数据的运行时类型信息 组件类型,即关于所包含元素的类型。 当使用有关组件类型的运行时类型信息时 元素存储在一个数组中,以确保没有“外星人” 元素可以插入。
有关详细信息,请查看here
答案 3 :(得分:2)
首先从问题2开始,然后回到问题1:
问题2:
&GT; ArrayList [] pl2 = new ArrayList [10]; ArrayList [] pl3 = new ArrayList [10];
就p12和p12的参考声明而言,有什么区别 p13有关吗?
在pl2中确保比p13更好的类型安全性。
如果我为pl2写道:
pl2[0]=new ArrayList<String>();
它会给我一个编译错误,说明&#34;无法从ArrayList<String>
转换为ArrayList<Integer>
&#34;
因此它确保了编译时的安全性。
但是,如果我写p13
pl3[0]=new ArrayList<String>();
pl3[1]=new ArrayList<Integer>();
它不会抛出任何错误,并且开发人员有责任在从p13中提取数据时正确编码和检查,以避免在运行时进行任何不安全的类型转换。
问题1:
这可能就是仿制药的工作方式。在主数组初始化期间,ArrayList<Integer>[] pl2 = new ArrayList[10]
,左侧ArrayList<Integer>[] pl2
,只有在索引位置初始化ArrayList对象时才能确保类型安全:
pl2[0]=new ArrayList<Integer>();
右侧主数组声明= new ArrayList[10]
只是确保索引位置将保存ArrayList类型的项。另请参阅 Type Erasure 中的类型擦除概念以获取更多信息。
答案 4 :(得分:2)
这不起作用,因为泛型类不属于Reifiable Types 。
JLS about Array creation expression州:
编译时错误 [类类型]不表示可再生类型(§4.7)。否则,[类类型]可以命名任何命名引用类型,甚至是抽象类类型(第8.1.1.1节)或接口类型(第9节)。
上述规则意味着数组创建表达式中的元素类型不能是参数化类型,而不是无界通配符。
Reifiable 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.
答案 5 :(得分:1)
问题1.
嗯,这不是正确的语法。因此,这不起作用。
问题2。
ArrayList<Integer>[] pl2 = new ArrayList[10];
ArrayList[] pl3 = new ArrayList[10];
由于pl2是用通用类型&lt; Integer&gt;定义的。在编译时,编译器将知道pl2只允许有整数,如果你尝试分配除整数之外的东西,你将收到警报,编译将失败。
在pl3中,由于没有泛型类型,您可以将任何类型的对象分配给列表。
答案 6 :(得分:0)
默认情况下,泛型问题由编译器发出警告。
编译后,由于类型擦除,它们都变为ArrayList[] pl2 = new ArrayList[10]
,但编译器警告你这不好。
泛型已添加到Java中,并且为了向后兼容,您可以互换地使用泛型和非泛型。
答案 7 :(得分:0)
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
答案 8 :(得分:0)
您无法创建参数化类型数组
ArrayList<Integer>[] pl2 = new ArrayList[10];
这意味着您告诉编译器您将创建将存储整数的arraylist的数组。您的arraylist将只包含Integer对象。这就是泛型的用武之地。泛型使您的代码更安全可靠。如果你确定你的列表应该只包含整数对象,你应该总是这样做。
但是当你说
时 ArrayList[] pl3 = new ArrayList[10];
这意味着arraylist可以存储任何对象类型,如字符串,整数,自定义对象等。
答案 9 :(得分:0)
根据an answer to Stack Overflow question Create an array of ArrayList elements,您似乎无法创建具有泛型类型的arraylists数组。
答案 10 :(得分:0)
据我所知,在Java中没有泛型这样的东西。在类型方面,ArrayList<Integer> and ArrayList
是相同的东西。
Java使用类型擦除来表示泛型。这意味着有关泛型的所有类型信息都在编译时被删除。所以ArrayList<Integer>
成为ArrayList。
所以这只是一个编译时的技巧。我猜,为了避免程序员可能做的任何混淆或错误,他们允许ArrayList<Integer>[]
实例化如下:new ArrayList[10]
。
所以ArrayList<Integer>[]
和ArrayList[]
是相同的,因为括号中的信息在编译时被删除。