как объявить Class.class с действительными обобщениями - PullRequest
4 голосов
/ 20 мая 2011

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

Мне интересно, есть ли способ объявить объект 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<?>> не являются?

РЕДАКТИРОВАТЬ: вопрос может быть обобщен до вопроса о вложенных параметрах необработанного типа. Например:

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

РЕДАКТИРОВАТЬ2: Я должен немного перефразировать вопрос: я знаю, что

Class<?> c = Class.class;

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

Ответы [ 3 ]

2 голосов
/ 20 мая 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>();

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

2 голосов
/ 20 мая 2011

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

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

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

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

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

2 голосов
/ 20 мая 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!
...