2012-05-24 1 views
4

Эта программа не компилируется:Java дженериков ошибка компиляции с участием класса <? extends T>

public class xx { 
    static class Class1<C> { 
     void method1(C p) { 
     } 
    } 
    static class Class2<T> extends Class1<Class<? extends T>> { 
     T object; 
     void method2() { 
      this.method1(this.object.getClass()); 
     } 
    } 
} 

Ошибка:

xx.java:10: method1(java.lang.Class<? extends T>) in xx.Class1<java.lang.Class<? extends T>> 
cannot be applied to (java.lang.Class<capture#215 of ? extends java.lang.Object>) 
     this.method1(this.object.getClass()); 

Почему это происходит? Почему компилятор, по-видимому, считает, что object.getClass() возвращает Class<? extends Object> вместо Class<? extends T>?

ответ

1

Object.getClass() определяется как возвращать Class<? extends |T|>, где T является статически известного типа приемника (объект getClass() называется на). Особо обратите внимание на вертикальные полосы, erasure operator. Стирание переменной типа - это стирание ее левого края. В вашем случае это неявная привязка Object. Итак, вы вернетесь Class<? extends Object>, а не Class<? extends T>.

Почему?

Представьте T = List<Integer>, вы можете внезапно сделать следующее без предупреждения неконтролируемого:

List<String> myStrings = new ArrayList<>(); 
List<Integer> myInts = new ArrayList<>(); 
List<Integer> myIntyStrings = myInts.getClass().cast(myStrings); 
myIntyStrings.add(-1); 
String myString = myStrings.get(0); // BANG! 

Но, к счастью, мы получаем предупреждение ..;)

+0

Спасибо, что уточняет это для меня! – Archie

4

В вашем коде отсутствует верхняя граница, установленная на T, поэтому ? extends T действительно равнозначно ? extends Object. Только вчера я сыграл с подобным примером и ударил этот барьер. У меня был

static <T> T newInstance(T o) throws Exception { 
    final Class<? extends T> c = o.getClass(); 
    return c.newInstance(); 
} 

и он жаловался на ту же ошибку. Рассмотрим это: возвращаемый тип Object.getClass() - Class<?>, и компилятор захочет захватить ? в конкретный тип. Но вместо этого мы хотели бы не записывать ?, а «захватить верхнюю границу» T - и такого нет в дженериках Java.

+0

Спасибо, что объясняет, почему мы получаем '? extends Object', но не из-за сбоя компиляции. Я имею в виду, не должен ли компилятор «знать», что 'object.getClass()' возвращает 'Class ', поскольку 'object' имеет тип' T'? – Archie

+0

Ответ отредактировал ... –

0

В соответствии с документацией на getClass() возвращаемый объект имеет тип Class< ? extends |X| >, где |X| - это стирание типа экземпляра, на который вызывается метод.

Поэтому вызов getClass() на объект типа T возвращает Class< ? extends Object >. В этом API нет связанной информации о T.

Обычно API, использующие отражение на общих классах, требуют, чтобы клиент передавал дополнительный аргумент типа Class<T> в соответствующий конструктор или общий метод.

Смежные вопросы