在Java中,为什么数组不能是类型变量绑定,但可以是通配符绑定?

时间:2011-01-23 17:09:43

标签: java arrays wildcard bounds type-parameter

在Java中,为什么数组不能是Type Variable的绑定,但可以是通配符的绑定?

你可以:

List< ? extends Integer[] > l;

但你不能拥有:

class MyClass< T extends Integer[] > { } // ERROR!

为什么?

3 个答案:

答案 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的理解,这样做是为了解决所有场景,如

  1. class MyClass< T extends Integer[] >
  2. class MyClass< T extends Integer[][] >
  3. ..
  4. class MyClass< T extends Integer[][]...[] >
  5. 因为所有这些都可以表示为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[]...
}

希望这会有所帮助,而且我的要求并不太远。