Проблемы при работе с картой<Class <?>, Object> в Java
public class MyClass<T> {
private Map<Class<?>, Object> member;
public <E> void putEnumSet(Class<E> enumSetType, E enumSet) {
this.member.put(enumSetType, enumSetType.cast(enumSet));
}
public <E> E getEnumSet(Class<E> enumType) {
return enumType.cast(this.member.get(enumType));
}
};
public enum Category {
// ...
};
member
в MyClass
используется для хранения нескольких видов EnumSet с различными типами Enum. При реализации относительных методов я сталкиваюсь с некоторыми проблемами: когда я пытаюсь вызвать метод следующим образом:
public static void main(String[] args) {
EnumSet<Category> set = EnumSet.noneOf(Category.class);
MyClass<Word> newClass = new MyClass<Word>();
newClass.putEnumSet(set.getClass(), set);
}
Здесь появляется ошибка:
Метод
putEnumSet(Class<E>, E)
в типеMyClass<Word>
не применимо для аргументов(Class<capture#1-of ? extends EnumSet>, EnumSet<Category>)
Как бороться с этой проблемой? Я думаю, что это может происходить из необработанного типа или стирания типа, но я не знаю основной причины. Благодарю.
2 ответа
Как бороться с этой проблемой?
E extends EnumSet<E>
Это очень запутанно, так как говорит, что у вас должен быть элемент E
который должен распространяться EnumSet<E>
т.е. вам нужен тип элемента, который сам по себе EnumSet
из E
У вас проблема с тем, что все классы EnumSet одинаковы во время выполнения. Т.е. есть только один класс EnumSet.class. Вам лучше записывать класс элементов.
public class MyClass {
private Map<Class, Set> member;
public <E> void putEnumSet(Class<E> elementType, Set<E> enumSet) {
this.member.put(elementType, enumSet);
}
public <E> Set<E> getEnumSet(Class<E> elementType) {
return (Set<E>) this.member.get(elementType));
}
};
Class
объекты могут быть сложны в использовании. Как вы заметили, их нелегко использовать с общими типами, потому что из-за стирания типов EnumSet<Category>.class
не является юридическим кодом Было бы невозможно использовать ваш подход к хранению EnumSet
для разных Enum
потому что есть только один Class
объект для всех EnumSet
с, а именно EnumSet.class
,
Одно решение, которое я нашел для этого, состоит в том, чтобы заменить Class<?>
с моим собственным ключевым объектом. Вот полная программа, демонстрирующая этот подход.
public class Main {
public enum Shape { SQUARE, CIRCLE, TRIANGLE }
// Here you would instantiate all the keys you will need.
public static final ClassKey<String> STRING_KEY = new ClassKey<String>();
public static final ClassKey<EnumSet<Shape>> SHAPE_SET_KEY = new ClassKey<EnumSet<Shape>>();
public static final class ClassKey<T> { private ClassKey() {} }
private Map<ClassKey<?>, Object> member = new HashMap<ClassKey<?>, Object>();
public <E extends Enum<E>> void putEnumSet(ClassKey<EnumSet<E>> enumSetType, EnumSet<E> enumSet) {
this.member.put(enumSetType, enumSet);
}
public <E extends Enum<E>> EnumSet<E> getEnumSet(ClassKey<EnumSet<E>> enumType) {
return (EnumSet<E>) member.get(enumType);
}
public static void main(String[] args) {
Main main = new Main();
EnumSet<Shape> enumSet = EnumSet.allOf(Shape.class);
main.putEnumSet(SHAPE_SET_KEY, enumSet);
EnumSet<Shape> shapes = main.getEnumSet(SHAPE_SET_KEY);
System.out.println(shapes);
}
}
Одним из основных недостатков этого подхода является то, что у вас должен быть фиксированный банк ClassKey
объекты. Это не будет работать для создания этих объектов на лету, потому что если вы использовалиnew ClassKey<EnumSet<Shape>>
положить EnumSet
в member
а потом попытался использовать new ClassKey<EnumSet<Shape>>
чтобы получить EnumSet
, вы обнаружите, что это не будет работать, потому что ключи не будут равны. Там нет никакого способа, чтобы написать equals()
метод для ClassKey
это работает, потому что из-за стирания типа было бы невозможно сказать ClassKey<EnumSet<Shape>>
из ClassKey<EnumSet<Category>>
,