Почему нельзя назначить I ‹? расширяет Type› до ‹Type›?

Следующие утверждения:

URLClassLoader ucl = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<URLClassLoader> uclc = ucl.getClass();

сбой с ошибкой:

Type mismatch: cannot convert from Class<capture#2-of ? extends URLClassLoader> to Class<URLClassLoader>

Зачем мне здесь гипс?

Я нашел несколько сообщений, объясняющих, почему вы не можете сделать обратное (присвоить T a ), но это (отчасти) очевидно и понятно.

ПРИМЕЧАНИЕ. Я кодирую это под eclipse Luna, поэтому я не знаю, является ли это причудой Луны или есть что-то, чего я действительно не понимаю в дженериках.


person ZioByte    schedule 09.06.2014    source источник


Ответы (2)


Ковариация, контравариантность, инвариантность

  • Class<? extends URLClassLoader> является инвариантным.

Как результат,

Class<? extends URLClassLoader> не является подтипом Class<URLClassLoader>


В Java переменная может содержать ссылку на экземпляр того же типа или подтипа.

Следовательно,

Class<URLClassLoader> uclc = ucl.getClass();

недействителен.

С другой стороны,

Class<? extends URLClassLoader> uclc = ucl.getClass();

будет действительным.

person Tanmay Patil    schedule 09.06.2014
comment
Можете ли вы уточнить, почему Class<? extends T> (или Class<?>) не является подтипом Class<T>? Я думаю, что это. - person skiwi; 09.06.2014
comment
@swiki: Попробуйте думать о коллекциях. Как вы думаете, Лист‹? extends Number› должен быть назначен List‹Integer›? Это приведет к проблемам безопасности типов и не допускается. Однако разрешено обратное назначение. - person Eyal Schneider; 09.06.2014
comment
Прочитайте это фантастическое объяснение: angelikalanger.com/GenericsFAQ/FAQSections/ - person Tanmay Patil; 09.06.2014
comment
@skiwi: типы - это диапазоны значений. Универсальные типы — это диапазоны типов. Class<? extends T> — это тип, который включает в себя все типы, производные от T. - person ninjalj; 09.06.2014

Почему нельзя назначить I ‹? расширяет Type› до ‹Type›?

Потому что на самом деле <? extends Type> является супертипом <Type>! Следим за спецификацией.

4.10.2 Подтипы среди классов и типы интерфейсов:

Учитывая объявление универсального типа C‹F1,...,Fn›, прямые супертипы параметризованного типа C‹T1 ,...,Tn› являются следующими:

  • C‹S1,...,Sn›, где Si содержит Ti.

4.5.1. Аргументы типа параметризованных типов:

Говорят, что аргумент типа T1 содержит другой аргумент типа T2, который записывается как T2 ‹= T1 , если множество типов, обозначенных T2, доказуемо является подмножеством множества типов, обозначенных T1, при рефлексивном и транзитивном замыкании следующих правил:

  • Т ‹= ? расширяет Т

Следовательно, мы знаем, что, поскольку ? extends URLClassLoader содержит URLClassLoader, Class<? extends URLClassLoader> является супертипом Class<URLClassLoader>.

Поскольку сокращение преобразования ссылок не допускается в контекст назначения, возникает ошибка компиляции.

Также обратите внимание, что это означает, что разрешено обратное присваивание:

Class<URLClassLoader> concrete = URLClassLoader.class;
Class<? extends URLClassLoader> wildcard = concrete;
person Radiodef    schedule 24.01.2015