как объявить Class.class с допустимыми дженериками

Примечание: исключительно из любопытства, а не для какого-либо реального варианта использования.

Мне интересно, есть ли способ объявить объект Class Class с допустимыми параметрами типа:

Class cc1 = Class.class; //raw type
Class<Class> cc2 = Class.class; //now parameter is raw type
Class<Class<?>> cc3 = Class.class; //compile error: inconvertible types

Если Class и Class<?> взаимозаменяемы, то почему Class<Class> и Class<Class<?>> нет?

EDIT: вопрос можно обобщить до вопроса о вложенных параметрах необработанного типа. Например:

ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList>(); //same compile error

EDIT2: я должен немного перефразировать вопрос: я знаю, что

Class<?> c = Class.class;

действителен, но мне интересно, почему Class<Class> не совпадает с Class<Class<?>>


person Paul Bellora    schedule 19.05.2011    source источник


Ответы (3)


У дженериков есть довольно серьезные ограничения. В этом случае вы не можете присвоить тип внутреннему типу Class<Class>, потому что на самом деле вы ссылаетесь на необработанный тип, а не на реализацию необработанного типа. Это даст вам предупреждение, но у вас нет возможности исправить это предупреждение.

Class<Class<?>> сам по себе не является непреобразуемым типом, вы просто не можете присвоить ему класс напрямую, потому что у него нет типа Class<Class<T>>, у него есть тип Class<T>.

Подумайте об этом по-другому; попробуй List<List<String>>. Чтобы создать это, вам нужно создать список, который принимает список строк. Это работает, потому что списки могут содержать списки.

Класс больше похож на примитив, чем на объект данных, поэтому я не думаю, что было бы возможно создать класс, который имеет тип класса чего-то другого.

Правка: ваш дополнительный вопрос о ArrayList<ArrayList<?>> является более очевидным примером проблемы с неконвертируемым типом, которая у вас возникла с Class<Class<?>>.

person Spyder    schedule 20.05.2011
comment
Приведенные выше ответы дали подробные объяснения дженериков/подстановочных знаков, но этот был ближе всего к тому, что я спрашивал, поэтому Class‹Class› не то же самое, что Class‹Class‹?››. Спасибо всем - person Paul Bellora; 20.05.2011

Правило здесь состоит в том, что универсальный тип в левой части должен соответствовать универсальному типу в правой части.

Class<?> означает класс любого типа.

Class<?> c = Class.class; 

Работает, потому что класс любого типа может быть Class<Class>.

Class<Class<?>> cc3 = Class.class;

Не работает, потому что тип Class.class - Class<Class>, который не имеет типа Class<Class<?>>

ArrayList<ArrayList<Integer>> lst = new ArrayList<ArrayList<Integer>>();
ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList<?>>();

Работает, потому что два выражения совпадают.

ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList>();

Не совпадать.

person Anthony Accioly    schedule 20.05.2011

Довольно сложно точно увидеть, что вы спрашиваете (или что вы пытаетесь сделать) ... но вы можете параметризовать без необработанных типов.

Class<? extends Object> cc4 = Class.class; // no raw types
Class<?> cc5 = Class.class; // also an option

Что касается вашего последнего примера, это не имеет смысла, потому что кажется, что вы хотите создать список массивов списков массивов, которые содержат ?, но ваше объявление не объявляет список массивов списков массивов, которые содержат ?.

Правильно написанный (но все еще не правильный Java) будет:

ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList<Integer>>(); // Type mismatch

Что ожидается. Это не работает по той же причине, что-то вроде следующего не работает:

Object o = new Object();
Integer i = new Integer(3);

o = i;
i.floatValue();
o.floatValue(); // can't access that method, we need to specifically cast it to Integer

Типы Java не выводятся заблаговременно (даже в цепочке наследования).

Однако, если вы хотите сохранить подстановочный знак, вы можете:

ArrayList<ArrayList<?>> lst = new ArrayList<ArrayList<?>>(); // works!
person David Titarenco    schedule 20.05.2011
comment
Идеальный ответ. Но я должен указать, что <? extends Object> — это то же самое, что и <?>, и это единственная причина совпадения выражения. - person Anthony Accioly; 20.05.2011