更新:尽管我已经找到了答案,但看来我对问题的描述不是很清楚。所以我做了很多修改,以使其他人理解我的问题。
我对为什么不允许使用参数化类型的数组的理解:
Integer[] b = {1,2,3};
Object[] a = b;
String[] c = {"123"};
a[0] = c; // Exception in thread "main" java.lang.ArrayStoreException
Integer i = b[0];
// Not really allowed.
List<String>[] lsa = new List<String>[10];
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
// Unsound, but passes run time store check
oa[1] = li;
// Run-time error: ClassCastException.
String s = lsa[1].get(0);
这两段代码具有相同的结构。
在第一篇中,Object[] a = b
使得a
和b
都指向同一个变量b
。因此a[0] = c
实际上正在更改b
。这种操作在编译时不会引起任何警告,但会引发ArrayStoreException。
在第二篇中,Object o = lsa; Object[] oa = (Object[]) o;
使得oa
和lsa
都指向同一个变量lsa
和oa[1] = li;
实际上正在更改lsa
。
所以我认为这就是为什么不允许使用参数化类型的数组的原因。
如果我的理解正确,那么T[] myArray
之类的情况也应拒绝。因为下面的代码也具有相同的结构。
import java.util.*;
public class Test {
public static <T> void test(T[] t) {
Object[] a = t;
String[] c = {"123"};
a[0] = c;
T i = t[0];
}
public static void main(String[] args) {
Integer[] t = {1,2,3};
test(t);
}
}
但是在Java教程中,
<T> T[] makeArray(T t) {
return new T[100]; // Error.
}
给出的原因是
由于类型变量在运行时不存在,因此无法确定实际的数组类型。
不是我期望的原因。
它也说
解决这些限制的方法是将类文字用作运行时类型标记
所以我在Generics gotchas找到了一个例子。 “未走的路”部分中的代码:
public class ArrayList<V> implements List<V> {
private V[] backingArray;
private Class<V> elementType;
public ArrayList(Class<V> elementType) {
this.elementType = elementType;
backingArray = (V[]) Array.newInstance(elementType, DEFAULT_LENGTH);
}
}
似乎使用类文字已经解决了使用类型为变量(T [])的数组的问题。但是我一开始提到的结构问题仍然存在。回想一下,我认为这三段代码的结构都不会导致编译警告,但会导致运行时错误。
那么,我的理解出了什么问题?
非常感谢您的时间:)
答案 0 :(得分:0)
第一个问题
为什么不允许使用参数化类型的数组?
我发现the answer
我可以创建一个其组件类型为具体参数化类型的数组吗?
否,因为它不是类型安全的。
然后,我试图解释示例代码为何引发异常?
java编译在编译期间未发现问题,每种类型的转换看起来都是合法的。 (ArrayStoreException是RuntimeException)
当您在String
中放置Integer Array
元素时,会发生异常。
您可以使用javac
和javap
查看字节码。
T[] t
的类型为Object [],因此变量a
(引用类型)将引用Integer[]
对象。当您将String
元素放入Integer Array
我认为问题与java泛型无关,所以我将示例更改如下以重现异常。
public class Test {
public static void main(String[] args) {
Integer[] t = {1,2,3};
Object[] a = t;
a[2] = "aaa";
}
}
答案 1 :(得分:0)
您已经发现,不能将元素分配给可更改类型的数组:
String[] ss = {""};
Object[] oo = ss;
oo[0] = 0; // ArrayStoreException
这是因为在运行时检查了数组元素的类型,可能是因为所有类型信息仍然可用。
但是对于通用数组,例如List<String>[]
,“ String”位在运行时不可用。因此,这将(名义上)有效:
List<String>[] lss = {Arrays.asList()};
Object[] oo = lss;
List<Integer> is = Arrays.asList(0);
oo[0] = is;
这会很好,因为所有可以检查的是您正在存储List
的实例。
但是,如果这样做,那么它将失败:
String s = lss[0].get(0); // ClassCastException
此故障可能发生在与导致该故障的任务相距很远的地方。
因此,不允许创建通用数组。
关于List<String>[]
和T[]
之间的区别:确实没有区别。 List<String>
是T
拥有的有效类型。
关键是您无法创建前者的实例:该类型的引用可以安全地获取的唯一值是null
。
似乎使用类文字已经解决了“类型变量在运行时不存在”的问题
否,因为类文字仅适用于非参数化类型:您可以通过传递ArrayList<String>
作为元素类型来创建String.class
。您无法创建ArrayList<ArrayList<String>>
,因为没有ArrayList<String>.class
。