我必须在这里感到困惑。
我到处都读到泛型参数化类型的数组是非法的。
来自AngelikaLanger的示例:
static void test() {
Pair<Integer,Integer>[] intPairArr = new Pair<Integer,Integer>[10] ; // error
addElements(intPairArr);
Pair<Integer,Integer> pair = intPairArr[1];
Integer i = pair.getFirst();
pair.setSecond(i);
}
来自Langer的引用(但我读到的其他地方都说同样的事情):
编译器禁止创建组件类型为a的数组 具体的参数化类型,就像我们的对 例。我们在前面的条目中讨论了为什么它是合理的 编译器将Pair []限定为非法。
到目前为止还好。
但在我的代码中:
private MyEntry<E> [] elements = (MyEntry<E>[])new Object[capacity];
我这样做,它编译得很好(我使用eclipse)但得到一个类强制转换异常错误(Object无法强制转换为MyEntry):
我的问题是,为什么这条线首先编译?
我认为编译器不允许这种实例化。
我在做什么错误/不同在这里?
更新:
在同一页面上,为什么我能够成功地做到:
List<E> elements[] = (List<E>[])new LinkedList[capacity];
并且没有运行时异常?
更新:
我读到的所有地方(因为经常引用兰格提到),它说编译器不允许这个声明(参数化类型的数组)。
我可以理解之后会发生什么
我无法理解编译器为什么不报告错误
我不是在评判,我说的是我读到的所有地方,它说这不会编译
我想念一些东西吗?
更新
我在new
部分看到了一些与缺失参数相关的评论
这也有否问题:
List<Entry<KeyType, ValueType>> table[] = (List<Entry<KeyType, ValueType>>[])new LinkedList[capacity];
答案 0 :(得分:2)
在您的第一个示例中,实例化没有问题 - 这正是您正在创建的内容:
new Object[capacity]
完全合法。但是,在尝试强制转换时会遇到运行时异常,因为Object
的数组不是MyEntry<E>
的数组。如果这些通用参数化的数组不存在,您可能会指出编译器可能会拒绝强制转换或声明,但这取决于擦除的顺序。无论如何,实例化本身都没问题。
在第二个示例中,您正在创建LinkedList
的非泛型数组。然后,您将其分配给通用引用,该引用在运行时将被擦除为List[]
。这工作正常(因为正确或错误,数组是协变的)。
我不确定为什么你期待运行时异常;与呼叫没什么不同,比如说
List<E> = new LinkedList();
你会收到一些未经检查的警告,但不会阻止代码编译或运行。
答案 1 :(得分:1)
因为LinkedList
是List
的实例。
但Object
不是MyEntry
的实例。
编译器也不检查是否可以将一个对象强制转换为另一个对象。因为它是运行时操作。
您应该使用:
private MyEntry<E> [] elements = new MyEntry [capacity];
或者:
class SomeOtherEntry extends MyEntry {}
private MyEntry<E> [] elements = new SomeOtherEntry [capacity];
但不是:
class SomeOtherEntry extends MyEntry {}
private SomeOtherEntry <E> [] elements = new MyEntry [capacity];
<强>更新强>
List<Entry<KeyType, ValueType>> [] table = (List<Entry<KeyType,ValueType>> []) new Linked[capacity];
答案 2 :(得分:1)
你完全误解了你所阅读的内容。使 type 是一个参数化类型的数组绝对没有错:MyEntry<E>[]
或HashMap<String,Integer>[][]
或其他什么。您可以随意使用这些类型的变量,并在可以使用任何类型的任何地方使用它们。
但是,在创建数组时,您无法执行new MyEntry<E>[...]
之类的操作。语言不允许这种情况(出于类型安全的原因,我们不会在这里讨论),因此这是一个编译错误。
最佳解决方案是new MyEntry[]
(原始类型数组)或new MyEntry<?>[]
(通配符类型数组);这两种语言都是允许的。它们都需要您明确地回放到MyEntry<E>[]
。
由于您询问了代码示例,因此您的第一个示例在语法上是正确的(new Object[...]
没有任何问题,并且在语法上可以转换为MyEntry<E>[]
),因此没有编译错误。但是,转换的运行时检查在运行时失败,因为对象的实际类型Object[]
不是MyEntry[]
的子类型。
第二个代码示例在语法上也是正确的,并且加上对转换成功的运行时检查(LinkedList[]
是List[]
的子类型。
答案 3 :(得分:0)
当您使用内置Java List类时,实际上会使用变通方法
<T> T[] toArray(T[] a)
方法。如果我们仔细看一下代码,如果您提供的数组小于所需的数组,则该方法实际上会创建一个新的类型参数数组。
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
...
}