Как сказать Карта класса‹?› перечислить‹Класс› в Java?

Скажем, у меня есть

HashMap<?, List<?>> map = new HashMap<>();
map.put(String.class, new ArrayList<Long>());

Следующий код будет скомпилирован.

Однако я хочу потерпеть неудачу при компиляции, потому что ArrayList не для типа String.

Кроме того, мой подстановочный знак ограничен каким-то конкретным интерфейсом (например, Exception), поэтому я полагаю, что должен где-то поместить этот <? extends Exception>.

Как я могу достичь вышеизложенного?

Пример теста:

map.put(String.class, new ArrayList<String>()); //Fail because String is not an Exception
map.put(IOException.class, new ArrayList<FileNotFoundException>()); // Fail because FileNotFoundException is not an IOException even though it is a subclass of it
map.put(FileNotFoundException.class, new ArrayList<IOException>()); // I suppose I'm fine with this.
map.put(IllegalArgumentException.class, new ArrayList<IllegalArgumentException>()); // Succeed
map.put(NumberFormatException.class, new ArrayList<ServerException>()); // Fail again because the two classes don't match
map.put(ClientDecodingException.class, new ArrayList<ClientDecodingException.class>); // Succeed again since the map takes in a wildcard Exception

person Lim    schedule 21.05.2015    source источник
comment
А как насчет Map<Class<T>, List<T>>?   -  person Luiggi Mendoza    schedule 21.05.2015
comment
@LuiggiMendoza, для которого потребуется где-то объявить <T>, и тогда ваша карта может содержать только классы/списки этого типа - у вас не может быть одновременно T = String и T = IOException.   -  person yshavit    schedule 21.05.2015
comment
@yshavit у вас может быть class MapOfClass, который работает как оболочка для Map<Class, List> (я буду использовать необработанные типы только в качестве примера) и имеет метод public <T> List<T> put(Class<T> clazz, List<T>> list). Это более подробно, но может решить проблему ОП.   -  person Luiggi Mendoza    schedule 21.05.2015
comment
Это один из обходных путей, да. (Вам даже не нужны необработанные данные, вы можете просто иметь Map<Class<?>, List<?>>.) Но конкретные требования OP не могут быть выполнены на Java.   -  person yshavit    schedule 21.05.2015
comment
Я новичок в java, но не могли бы вы просто определить свой собственный класс hashmap, который расширяет hashmap и перегружает так, чтобы он не был универсальным, а принимал только типы исключений в качестве аргумента?   -  person Kevin    schedule 21.05.2015
comment
@HyperZ в подобных случаях лучше использовать композицию, а не наследование.   -  person Luiggi Mendoza    schedule 21.05.2015
comment
Спасибо всем, я так и подозревал, но просто хотел проверить с сообществом, не пропустил ли я что-нибудь =) @LuiggiMendoza: Мне интересно услышать о подходе композиции к наследованию, что вы имеете в виду, не могли бы привести конкретный пример?   -  person Lim    schedule 22.05.2015


Ответы (2)


Я считаю, что вы не можете выразить такое общее ограничение между ключом вашей карты и значением при объявлении. Вы можете объявить карту как

    Map<Class<Exception>, List<Exception>>

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

Я не вижу много способов проверить это ограничение, кроме как с помощью такого метода, как

    <T extends Exception> void addToMap(Class<? extends T> aClass, List<T> aList) { 
        map.put(aClass, aList); 
    }

Надеюсь это поможет.

person Mehdi.    schedule 21.05.2015

Я сделал это, используя необработанные Class и List (до сих пор не могу исправить это) и используя оболочку карты для хранения только Exception:

public class ExceptionMapWrapper {

    private Map<Class, List> myMap;

    public ExceptionMapWrapper() {
        myMap = new HashMap<>();
    }
    //relevant methods for the test: put and get
    public <T extends Exception> void put(Class<T> clazz, List<T> list) {
        myMap.put(clazz, list);
    }

    public <T extends Exception> List<T> get(Class<T> key) {
        return myMap.get(key);
    }
}

И простой тест для этого:

ExceptionMapWrapper exceptionMapWrapper = new ExceptionMapWrapper();
Class<IOException> clazz = IOException.class;
List<IOException> list = new ArrayList<>();
exceptionMapWrapper.put(clazz, list);
//compiler errors, uncomment to see them
//exceptionMapWrapper.put(String.class, new ArrayList<String>());
//exceptionMapWrapper.put(IOException.class, new ArrayList<ClassCastException>());
//exceptionMapWrapper.put(IOException.class, new ArrayList<SQLException>());
List<IOException> ioExList = exceptionMapWrapper.get(clazz);
//compiler error, uncomment to see
//List<SQLException> sqlExList = exceptionMapWrapper.get(clazz);
person Luiggi Mendoza    schedule 22.05.2015