11

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

你可以有:

List< ? extends Integer[] > l;

但你不能拥有:

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

为什么?

4

3 回答 3

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 编译器会将其视为 a 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[][]...[] >

因为它们都可以表示为java.lang.Object并且当作为参数传递时,如示例

public Genric(E c){
            System.out.println(c.getClass().getName());
        }

因为'c'记住了它的真实类型。

希望这会有所帮助。

于 2011-01-23T19:28:35.593 回答
3

我正在尝试考虑应该禁止这样做的具体原因,但我唯一能想到的是这是一个完全不必要的结构,因为:

class Foo<T extends Integer[]> {
   T bar();
}

相当于

class Foo<T extends Integer> {
   T[] bar();
}

显然,通配符情况不能说相同,因此它是允许的。

于 2011-01-23T19:27:47.353 回答
0

您可以执行以下操作:

public class MyClass<K> {
    K array;
    public MyClass(K k) {
       array = k;
    }

或者你可以做这样的事情:

class MyClass< T extends Integer > {
   ...make your variable MyClass[]...
}

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

于 2011-01-23T18:02:10.790 回答