В Java, почему массив не может быть переменной типа Variable, но может быть привязкой подстановочного знака?
У вас может быть:
List< ? extends Integer[] > l;
но вы не можете:
class MyClass< T extends Integer[] > { } // ERROR!
Почему?
В Java, почему массив не может быть переменной типа Variable, но может быть привязкой подстановочного знака?
У вас может быть:
List< ? extends Integer[] > l;
но вы не можете:
class MyClass< T extends Integer[] > { } // ERROR!
Почему?
Рассмотрим этот код 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' запоминает свой истинный тип.
Надеюсь, это поможет.
Я пытаюсь думать о конкретных причинах, по которым это должно быть запрещено, но единственное, о чем я могу думать, это то, что это абсолютно ненужная конструкция, потому что:
class Foo<T extends Integer[]> {
T bar();
}
эквивалентно
class Foo<T extends Integer> {
T[] bar();
}
Очевидно, то же самое нельзя сказать о корпусе шаблона, следовательно, это разрешено.
Вы можете сделать что-то вроде:
public class MyClass<K> {
K array;
public MyClass(K k) {
array = k;
}
Или вы можете сделать что-то вроде этого:
class MyClass< T extends Integer > {
...make your variable MyClass[]...
}
Надеюсь, это поможет, и я не слишком далеко от того, о чем вы просили.