2009-05-16 7 views
6

Есть ли способ сделать следующую реализацию безопасным способом?Java Generics, помещая на карту <String,? extends Список <String>>

public void myMethod(Map<String, ? extends List<String>> map) 
{ 
    map.put("foo", Collections.singletonList("bar"); 
} 

Вышеуказанная реализация не работает. Для правильной компиляции метода map.put() требуется Map<String, ? super List<String>>. Но myMethod не будет принимать какой-либо подтип List в этом виде. Итак, я должен использовать Map<String, ? extends List<String>>. Как я могу решить эту проблему безопасным образом?

ответ

20
public void myMethod(Map<String, List<String>> map) { 
    map.put("foo", Collections.singletonList("bar")); 
} 

Вы не можете поставить List (тип возвращаемого Collections.singletonList() в Map из ? extends List, так как фактический тип может быть любая реализация List. Например, это не безопасно поставить общий List в Map<String,LinkedList> с List не может быть LinkedList. Тем не менее, мы можем легко положить LinkedList в Map из <String,List>.

Я думаю, что вы ш прежде чем думать о своих дженериках. Вам не нужно использовать ? extends для не-общего класса. Например, List<Object> будет содержать любые Object, ? extends не требуется для добавления объекта. A List<List<Foo>> будет принимать только List<Foo> объектов, а не List<FooSubclass> объектов [Родовые классы не наследуются на основе их параметров]. Здесь ? extends вступает в игру. Чтобы добавить как List<Foo>, так и List<FooSubclass> в List, тип должен быть List<List<? extends Foo>>.

+2

+1 для хорошего объяснения (теперь, когда ваши дженерики видны: P). –

+0

К сожалению. Я продолжаю думать, что, поскольку SOF фильтрует текст так или иначе, что он фиксирует скобки. Ну что ж... – KitsuneYMG

6

Не было Map<String, List<String> Работает? Есть ли какая-то особая причина, по которой вы должны иметь подстановочный знак?

0

Представьте, что кто-то передал вам Map<String, ArrayList<String>>. Значение, которое вы вставляете, является результатом Collections.singletonList, который равен , а не a ArrayList.

Вы не можете принять какой-либо подтип списка на карте, а затем ожидать, что сможете добавить свой собственный, возможно, несовместимый подтип.

4

Существует очень простой принцип использования коллекций и дженериков. Это называется «Принцип Get и The Put»:

Используйте подстановочный символ «extends», когда вы только GET выставляете значения из коллекции, используйте «супер» подстановочный знак, когда вы вводите только значения PUT в коллекцию и не используете любой подстановочный знак, когда вы хотите получить и поставить.

Итак, как вы можете видеть, исходный пример недействителен в соответствии с этим принципом.

Смежные вопросы