Как работает <? extends SomeClass> в Map<K,V>?

104
10 декабря 2021, 08:50

Есть два класса EJPlayer (Интерфейс) и EPlayer (Дочерний)

Есть массив ConcurrentHashMap<String,? extends EJPlayer>

По логике EPlayer же должен помещаться в этот массив? По итогу ошибка в методе put(k,v)

Код:

public class EPlayer implements EJPlayer {
    protected static ConcurrentHashMap<String,? extends EJPlayer> registeredEPlayers = new ConcurrentHashMap<>();
    public static EJPlayer registerEPlayer(Player p) {
        return EPlayer.registeredEPlayers.put(p.getName(), new EPlayer(p)); // Ошибка тут
    }
    public static EJPlayer getEPlayer(Player p) {
        if (EPlayer.registeredEPlayers.containsKey(p.getName()))
            return EPlayer.registeredEPlayers.get(p.getName());
        else
            return EPlayer.registerEPlayer(p);
    }
}

Класс EJPlayer (Методы указанные тут есть в EPlayer)

public interface EJPlayer {
    public Player getPlayer();
    public ReadOnlySettings getSettings();
}
Answer 1

Как решить вашу проблему:

Конкретно ваша задача решается использованием базового типа в рамках generic'а вместо wildcard, как вы и описали выше:

protected static ConcurrentMap<String, EJPlayer> registeredEPlayers = new ConcurrentHashMap<>();

Рекомендации:

  • В Java принято работать с интерфейсами, а не с их реализацией, именно поэтому, в блоке кода, приведенном мною выше, в качестве типа переменной используется ConcurrentMap (возможно, вам даже будет достаточно и просто интерфейса Map), а не ConcurrentHashMap.
  • Если ваше статическое поле с Map'ой, потенциально, не должно никогда переприсваиваться, то лучше сразу объявите его как final (тогда по рекомендациям и переменную назовете в верхнем регистре, т.к. она станет static final).

Про wildcard generics:

Вопрос же касательно wildcard generic'ов, на самом деле, совсем нетривиальный. Если вкратце, то существует принцип The Get and Put Principle, он же PECS (Producer Extends Consumer Super)):

  • Если объявить wildcard с использованием extends, то это producer. Он только предоставляет элемент из контейнера, а сам ничего не принимает (за исключением null).
  • Если же объявить wildcard с использованием super, то это consumer. Он только принимает, а предоставить ничего не может (за исключением Object).

Подробнее с этой особенностью wildcard generic в Java можете ознакомиться здесь и здесь.

Answer 2

Поменял <String,? extends EJPlayer> на <String,EJPlayer> и всё заработало.. Извиняюсь за флуд в ленте)

READ ALSO
Программа не работает. В чем ошибка? [закрыт]

Программа не работает. В чем ошибка? [закрыт]

Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском

177
Простой Junit test для метода в Java

Простой Junit test для метода в Java

Только начинаю постигать полезности тестированияПеречитал много ответов здесь и в гугле в целом, но ответа не нашел

192
SQLite + Hibernate

SQLite + Hibernate

Не получается задать относительный путьПосле создания артефакта (IDEA) при открытии сессии выводит ошибку: javax

76
Как правильно создавать модели данных

Как правильно создавать модели данных

Делаю приложение "Список дел/задач"

158