Java map with values limited by key's type parameter
Java-карта со значениями, ограниченными параметром типа ключа
Есть ли в Java способ создать карту, в которой параметр типа значения привязан к параметру типа ключа? Я хочу написать что-то вроде следующего:
publicclassFoo { // This declaration won't compile - what should it be? privatestatic Map<Class<T>, T> defaultValues;
// These two methods are just fine publicstatic <T> voidsetDefaultValue(Class<T> clazz, T value) { defaultValues.put(clazz, value); }
publicstatic <T> T getDefaultValue(Class<T> clazz) { return defaultValues.get(clazz); } }
То есть я могу сохранить любое значение по умолчанию для объекта класса при условии, что тип значения совпадает с типом объекта класса. Я не понимаю, почему это не должно быть разрешено, поскольку я могу гарантировать при установке / получении значений, что типы верны.
РЕДАКТИРОВАТЬ: Спасибо клетусу за его ответ. На самом деле мне не нужны параметры типа на самой карте, поскольку я могу обеспечить согласованность методов, которые получают / устанавливают значения, даже если это означает использование некоторых немного уродливых приведений.
Переведено автоматически
Ответ 1
Вы же не пытаетесь реализовать типобезопасный гетерогенный шаблон контейнера Джошуа Блоха, не так ли? В основном:
Это класс Key. Обратите внимание, что тип T никогда не используется в этом классе! Это исключительно для приведения типов при считывании значения из map. Поле key дает ключу только имя.
public Collection<Object> values() { return delegate.values(); }
}
Ответ 3
Нет, вы не можете сделать это напрямую. Вам нужно будет написать класс-оболочку вокруг Map<Class, Object> чтобы обеспечить, чтобы объект был instanceof классом.
Ответ 4
Можно создать класс, который хранит сопоставление типа safe key со значением и приводит его при необходимости. Метод cast in get безопасен, поскольку после использования new Key<CharSequence>() его невозможно безопасно преобразовать в Key<String> или Key<Object>, поэтому система типов обеспечивает правильное использование класса.
Key Класс должен быть окончательным, так как в противном случае пользователь может переопределить equals и вызвать небезопасность типа, если два элемента с разными типами будут равны. В качестве альтернативы можно переопределить equals, чтобы быть окончательным, если вы хотите использовать наследование, несмотря на проблемы с ним.
publicfinalclassTypeMap { privatefinal Map<Key<?>, Object> m = newHashMap<>();
public <T> T get(Key<? extends T> key) { // Safe, as it's not possible to safely change the Key generic type, // hash map cannot be accessed by an user, and this class being final // to prevent serialization attacks. @SuppressWarnings("unchecked") Tvalue= (T) m.get(key); return value; }
public <T> voidput(Key<? super T> key, T value) { m.put(key, value); }