0
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 type MyClass<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.

2 Answers 2

1

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));
    }
};
Sign up to request clarification or add additional context in comments.

6 Comments

Oh, that's right, after type erasure, all EnumSets are of the same type, EnumSet.class. Using element type as a key is exactly a good idea. While, would you please explain the error (Class<capture#1-of ? extends EnumSet>, EnumSet<Category>), since I am still confused about it?
@stanleyerror the confusing part is that your E type must extends an EnumSet<E> i.e. you have a recursive definition.
Finally the Map<Class<?>, Object> member is like: [String.class -> Set<String>, Integer.class -> Set<Integer>, ..., Enum1.class -> EnumSet<Enum1>, Enum2.class -> EnumSet<Enum2>, ...]. Is there a way to judge whether a key of member is a Enum's class? Sorry to bother you again.
@stanleyerror all enum extend the class Enum , if that is what you mean.
@stanleyerror you have a number of unrelated questions. To test whether a key is a member of an enum you can check if (key instanceof Enum) Instance of Enum1 can be assigned to an Enum<Enum1>. The class as it's instances have different types. Class<?> is an unknown class which will only allow operations where the type is not used. Class will allow any operation.
|
1

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 EnumSets for different Enums because there is only one Class object for all EnumSets, 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>>.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.