Reputation: 788
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 {
// ...
};
The member
in MyClass
is used to store several kinds of EnumSet with different Enum type. While implementing relative methods, I meet some problems: when I try to call the method like this:
public static void main(String[] args) {
EnumSet<Category> set = EnumSet.noneOf(Category.class);
MyClass<Word> newClass = new MyClass<Word>();
newClass.putEnumSet(set.getClass(), set);
}
Here comes the error:
The method
putEnumSet(Class<E>, E)
in the typeMyClass<Word>
is not applicable for the arguments(Class<capture#1-of ? extends EnumSet>, EnumSet<Category>)
How to deal with this problem? I think it may come from raw type or type erasure, but I do not know the main reason. Thanks.
Upvotes: 0
Views: 173
Reputation: 37655
Class
objects can be difficult to use. As you have noticed, they're not easy to use with generic types because due to type erasure EnumSet<Category>.class
is not legal code. It would be impossible to use your approach to store EnumSet
s for different Enum
s because there is only one Class
object for all EnumSet
s, namely EnumSet.class
.
One solution I have found to this is to replace Class<?>
with my own key object. Here is a complete program demonstrating this approach.
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);
}
}
One major drawback to this approach is that you have to have a fixed bank of ClassKey
objects. It would not work to create these objects on the fly because if you usednew ClassKey<EnumSet<Shape>>
to put an EnumSet
into member
and then tried to use new ClassKey<EnumSet<Shape>>
to retrieve the EnumSet
, you would find it would't work because the keys would not be equal. There is no way to write an equals()
method for ClassKey
that works because, due to type erasure, it would be impossible to tell a ClassKey<EnumSet<Shape>>
from a ClassKey<EnumSet<Category>>
.
Upvotes: 1
Reputation: 533870
How to deal with this problem?
E extends EnumSet<E>
This is very confusing as it says you have to have a element E
which must extend EnumSet<E>
i.e. you need an element type which is itself an EnumSet
of E
You have a problem that all EnumSet classes are the same at runtime. I.e. there is only one EnumSet.class. You are better off recording the class of elements.
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));
}
};
Upvotes: 1