Универсальные шаблоны и подстановочные знаки java.lang.Class

Почему следующий код не компилируется?

interface Iface<T> { }

class Impl<T> implements Iface<T> { }

class TestCase {
    static Class<? extends Iface<?>> clazz = Impl.class;
}

Ошибка

Java: несовместимые типы: java.lang.Class<Impl> нельзя преобразовать в java.lang.Class<? extends Iface<?>>

но я не понимаю, почему подстановочный знак не захватывает.


person Tavian Barnes    schedule 07.05.2015    source источник
comment
См. также Невозможно преобразовать из List‹List› в List‹List‹?›› для расширенное объяснение. (Вы пытаетесь преобразовать Class<Impl> в Class<? extends Iface<?>>, поэтому, по сути, применяются те же правила.) Если вам это действительно нужно, то можно использовать его так, как я описал здесь. (Class<? extends Iface<?>>)(Class<? extends Impl>)Impl.class В противном случае избегайте необработанных аргументов типа.   -  person Radiodef    schedule 07.05.2015
comment
@Radiodef Спасибо за эту ссылку! К сожалению, приведение не работает для параметров аннотации, что является реальным вариантом использования, который вызвал этот вопрос.   -  person Tavian Barnes    schedule 07.05.2015
comment
Ой. Я не уверен, что предложить тогда. Вы могли бы изменить свою аннотацию на Class<? extends Iface>, но это э. Зависит от того, для чего вы используете класс. Вы могли бы аннотировать это таким образом, а затем применить клудж.   -  person Radiodef    schedule 07.05.2015


Ответы (2)


Отношения подтипа здесь:

          Class<? extends Iface>
           ╱                  ╲
Class<? extends Iface<?>>   Class<Impl>

(Что я объяснил в своем ответе на

person Radiodef    schedule 07.05.2015

Из-за type-erasure, когда вы говорите Impl.class, вы получаете Class<Impl>. То есть можно сказать

Class<Impl> clazz = Impl.class;

Обобщения — это функция безопасности типов во время компиляции.

person Elliott Frisch    schedule 07.05.2015
comment
Но другие подобные конструкции, такие как Class<? extends CharSequence> clazz = String.class, работают. Это также работает, когда я пишу class Impl implements Iface<String> { } или Class<? extends Iface> clazz. - person Tavian Barnes; 07.05.2015
comment
@TavianBarnes Суть в том, что String не принимает никаких общих аргументов - как вы указываете, если Impl не имеет общих аргументов, он также работает нормально. (Обратите внимание, что оба этих класса наследуют от других классов, которые имеют общие параметры, это нормально — если класс имеет общий параметр сам по себе, это создает трудности для компилятор (из-за стирания типа.) - person Michael Berry; 07.05.2015
comment
@ berry120 А, ладно, теперь это имеет для меня смысл. Необработанный тип Impl в Class<Impl> вызывает стирание всех типов в иерархии Impl, поэтому фактически у нас есть Impl extends Iface, но не Impl extends Iface<?> для любого ?. Спасибо! - person Tavian Barnes; 07.05.2015