stanleyerror
stanleyerror

Reputation: 788

Problems when operating on Map<Class<?>, Object> in 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 {
    // ...
};

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.

Upvotes: 0

Views: 173

Answers (2)

Paul Boddington
Paul Boddington

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 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>>.

Upvotes: 1

Peter Lawrey
Peter Lawrey

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

Related Questions