Ограничьте универсальный параметр Class для классов, которые реализуют Map - PullRequest
0 голосов
/ 18 февраля 2019

Я пытаюсь написать Map строитель.Один из конструкторов позволит клиенту указать тип Map, который он хочет построить

public class MapBuilder<K, V> {

    private Map<K, V> map;

    /**
     * Create a Map builder
     * @param mapType the type of Map to build. This type must support a default constructor
     * @throws Exception
     */
    public MapBuilder(Class<? extends Map<K, V>> mapType) throws Exception {
        map = mapType.newInstance();
    }

    // remaining implementation omitted
}

Цель состоит в том, чтобы иметь возможность создавать экземпляры компоновщика с помощью:

MapBuilder<Integer, String> builder = new MapBuilder<Integer, String>(LinkedHashMap.class);

или

MapBuilder<Integer, String> builder = new MapBuilder<Integer, String>(HashMap.class);

Похоже, что сигнатура типа аргумента конструктора в настоящее время не поддерживает это, потому что строка выше вызывает ошибку компиляции "Cannotize constructor".

Как я могу изменить свой конструктор так, чтобы он принимал классы, которые реализуют только Map?

Ответы [ 3 ]

0 голосов
/ 18 февраля 2019

Используйте Supplier вместо Class:

public MapBuilder(Supplier<? extends Map<K, V>> supplier) {
    map = supplier.get();
}

Что затем можно назвать так:

MapBuilder<Integer, Integer> builder = new MapBuilder<>(LinkedHashMap::new);

Это также безопаснее, потому что Class<Map> может не иметь конструктора по умолчанию, который выдаст ошибку (что не очень отзывчивый код)

0 голосов
/ 18 февраля 2019

Проблема в том, что LinkedHashMap.class это

Class<LinkedHashMap>

, а не что-то вроде

Class<LinkedHashMap<Integer, String>>

Это также необратимые типы (так что вы не можете разыграть их), и нетспособ получить экземпляр последнего.

Что вы можете сделать, это изменить конструктор на

public MapBuilder(Class<? extends Map> mapType) throws Exception

Во время выполнения стираются универсальные элементы, поэтому во время выполнения все Map сбудет вести себя так же, как Map<Object, Object> в любом случае.Поэтому не имеет значения, что класс, из которого вы строите, использует необработанный тип.


Кстати, Class::newInstance устарело.Используйте

mapType.getConstructor().newInstance()
0 голосов
/ 18 февраля 2019

Будет работать следующее:

public MapBuilder(Class<? extends Map> mapType) throws Exception {
    map = mapType.newInstance();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...