2015-12-18 3 views
2

У меня есть две карты Something1 и Something2. Оба расширяют класс Something.Проблема с генериками и переменным назначением

Map<Class<? extends Something1>, String> m1 
Map<Class<? extends Something2> ,String> m2 

Я хочу, чтобы создать более общую карту m3, к которым я могу назначить m1 или m2 вроде этого:

Map<Class<? extends Something>, String> m3 = m1; 

Однако я получаю следующее исключение:

Type mismatch: cannot convert from Map<Class<? extends Something1>, String> to Map<Class<? extends Something>, String> 

Я также попробовал использовать Class<?>, но он не работает.

Что я делаю неправильно?

+3

Читать эту answer - http://stackoverflow.com/a/19220458/1679863, чтобы понять, как работают многоуровневые общие типы. После этого вы сможете понять, что изменение вашей третьей карты на: «Карта , String> = m1; 'будет работать. –

+1

Большое вам спасибо! Это устранило мою проблему – user1534960

ответ

2

это невозможно. Рассмотрим следующий пример:

Map<Class<? extends Something1>, String> m1 = new HashMap<>(); 
m1.put(Something1.class, "Something1"); // OK 
m1.put(Something2.class, "Something2"); // Error 

Таким образом, вы не можете поставить Something2 в качестве ключа.

Другой путь:

Map<Class<? extends Something2>, String> m2 = new HashMap<>(); 
m2.put(Something1.class, "Something1"); // Error 
m2.put(Something2.class, "Something2"); // OK 

Здесь вы не можете поставить Something1 в качестве ключа.

Но, если вы создаете версию, которая использует базовый класс в качестве шаблона, он работает. Проверьте это:

Map<Class<? extends Something>, String> m = new HashMap<>(); 
m.put(Something1.class, "Something1"); // OK 
m.put(Something2.class, "Something2"); // OK 

Ваша проблема заключается в том, что вы пытаетесь назначить более конкретный тип родовому типу. Например:

m = m1; // Boom, but why? 

Почему это не работает. Ну, это потому, что если вы позволите, что назначение вы могли бы сделать это:

m.put(Something2.class, "Something2"); 

который, очевидно, не будет нормально с тех пор вы положили бы Something2 в качестве ключа для Something1 типа карты.

0

Аргументы типа без подстановочных знаков должны быть точно такими же, чтобы быть совместимыми. Class<? extends Something1> не совсем то же самое, что и Class<? extends Something> (хотя один из них является подтипом другого), и поэтому Map одного из них несовместим с Map другого.

Если вы хотите, тип, который может принимать Map S с различными аргументами типа, вам нужно уайлдкард на верхнем уровне (хотя заметим, что это будет эффективно сделать Map только для чтения):

Map<? extends Class<? extends Something>, String> m3 = m1; 
Смежные вопросы