在Java中,为什么数组不能是Type Variable的绑定,但可以是通配符的绑定?
你可以:
List< ? extends Integer[] > l;
但你不能拥有:
class MyClass< T extends Integer[] > { } // ERROR!
为什么?
答案 0 :(得分:7)
考虑这个Java代码:
package test;
public class Genric<E>
{
public Genric(E c){
System.out.println(c.getClass().getName());
}
public static void main(String[] args) {
new Genric<Integer[]>(new Integer[]{1,2});
}
}
对于您的第一个案例:
List< ? extends Integer[] > l;
当您执行此类List< ? extends Integer[] > l;
之类的操作时,Java编译器会将其视为List< ? extends Object> l;
并进行相应的转换。所以这就是你没有得到任何错误的原因。
生成的字节码如下:
.
.
.
20: aastore
21: invokespecial #52; //Method "<init>":(Ljava/lang/Object;)V
24: return
.
.
检查行号 21 。虽然,我已经通过了java.lang.Integer
的数组;在内部,它被翻译为java.lang.Object
。
对于您的第二种情况:
class MyClass< T extends Integer[] > { } // ERROR!
根据java语言规范:
TypeParameter:
TypeVariable TypeBoundopt
TypeBound:
extends ClassOrInterfaceType AdditionalBoundListopt
.
.
正如您所看到的,绑定仅由类或接口组成(甚至不是基本类型)。因此,当您执行此类class MyClass< T extends Integer[] > { }
之类的操作时,Integer[]
不符合类或接口的条件。
根据我对Java Spec的理解,这样做是为了解决所有场景,如
class MyClass< T extends Integer[] >
class MyClass< T extends Integer[][] >
class MyClass< T extends Integer[][]...[] >
因为所有这些都可以表示为java.lang.Object
并且作为参数传递时,例如
public Genric(E c){
System.out.println(c.getClass().getName());
}
因为'c'记得它的真实类型。
希望这会有所帮助。
答案 1 :(得分:3)
我正在考虑应该禁止的具体原因,但我能想到的唯一原因是它是一个完全不必要的构造,因为:
class Foo<T extends Integer[]> {
T bar();
}
相当于
class Foo<T extends Integer> {
T[] bar();
}
显然对于通配符情况也是如此,因此它是允许的。
答案 2 :(得分:0)
您可以执行以下操作:
public class MyClass<K> {
K array;
public MyClass(K k) {
array = k;
}
或者你可以这样做:
class MyClass< T extends Integer > {
...make your variable MyClass[]...
}
希望这会有所帮助,而且我的要求并不太远。