Рассмотрим этот код 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' помнит его истинный тип.
Надеюсь, это поможет.