В Java, почему массив не может быть границей переменной типа, но может быть границей подстановочного знака? - PullRequest
10 голосов
/ 23 января 2011

Почему в Java массив не может быть границей переменной типа, но может быть знаком подстановочного знака?

Вы можете иметь:

List< ? extends Integer[] > l;

но вы не можете иметь:

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

Почему?

Ответы [ 3 ]

7 голосов
/ 23 января 2011

Рассмотрим этот код 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[][]...[] >

Поскольку все они могут быть представлены как java.lang.Object и при передаче в качестве параметра, как в примере

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

как'c' помнит его истинный тип.

Надеюсь, это поможет.

3 голосов
/ 23 января 2011

Я пытаюсь подумать о конкретных причинах, это должно быть запрещено, но я могу думать только о том, что это совершенно ненужная конструкция, потому что:

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

эквивалентно

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

Очевидно, что то же самое нельзя сказать о случае с подстановочными знаками, поэтому он разрешен там.

0 голосов
/ 23 января 2011

Вы можете сделать что-то вроде:

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

Или вы можете сделать что-то вроде этого:

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

Надеюсь, это поможет, и я не слишком далеко от того, что вы спрашивалидля.

...