Java Generics положить на карту <String,? расширяет список <String>> - PullRequest
6 голосов
/ 16 мая 2009

Есть ли способ сделать следующую реализацию безопасным для типов?

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>> вместо этого. Как я могу решить эту проблему безопасным способом?

Ответы [ 4 ]

20 голосов
/ 16 мая 2009
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 не требуется для добавления объекта. List<List<Foo>> будет принимать только List<Foo> объекты, а не List<FooSubclass> объекты [Универсальные классы не наследуют в зависимости от своих параметров]. Здесь ? extends вступает в игру. Чтобы добавить List<Foo> и List<FooSubclass> к List, тип должен быть List<List<? extends Foo>>.

6 голосов
/ 16 мая 2009

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

4 голосов
/ 06 октября 2009

При использовании коллекций и обобщений существует очень простой принцип. Он называется «Принцип получения и сдачи»:

Используйте подстановочный знак "extends", когда вы только получаете значения GET из коллекции, используйте подстановочный знак "super", когда вы только помещаете значения в коллекцию, и не используйте подстановочный знак, когда хотите получить и поставить.

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

0 голосов
/ 16 мая 2009

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

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

...