Generic Map of Generic key/values with related types

。_饼干妹妹 提交于 2019-12-18 18:56:18

问题


I'm trying to create a generic type that keeps a map of the versions of itself that have been created for later use. Effectively, it's an singleton pattern where there's one instance per type. The code I have so far is:

public class FieldBinder<T> {
    static final Map<Class<? extends Object>,FieldBinder<? extends Object>> instanceMap = 
        new HashMap<Class<? extends Object>,FieldBinder<? extends Object>>();

    private FieldBinder() {}

    synchronized public static <V extends Object> FieldBinder<V> getInstance(Class<V> klass) {
        if(!instanceMap.containsKey(klass)) {
            instanceMap.put(klass, new FieldBinder<V>());
        }
        return (FieldBinder<V>)instanceMap.get(klass);
    }
}

However, I'm still unsure that I'm "doing it right". It feels like I should be able to specify that the collection is (Class -> FieldBinder). The fact that the IDE is warning about the return statement only reinforces this thought.

Is there a better way to handle this?

Note: This question seems very closely related, but just far enough away that I can't figure out how to apply the information in it to my own problem.


回答1:


Your implementation is correct. There's no "better" way of doing it (if there is such a thing is "better" in code, which is another issue..)

Minor fixes:

  • <V extends Object> is equivalent to V which is less verbose
  • Class<? extends Object> is equivalent to Class<?> which is less verbose
  • You can use the @SuppressWarnings("unchecked") annotation to tell your compiler that the cast is safe



回答2:


I don't think it can be done without having an unchecked cast somewhere. You would need something similar to Haskell's existential types, which Java does not have.

You could make the client perform the unchecked cast instead...

synchronized public static <V> FieldBinder<V>
getInstance(Class<V> klass, Class<FieldBinder<V>> binderKlass) {
    if(!instanceMap.containsKey(klass)) {
        instanceMap.put(klass, new FieldBinder<V>());
    }
    return binderKlass.cast(instanceMap.get(klass));
}

Now if the client passes a Class<FieldBinder<V>> to the getInstance() method you can avoid the unchecked cast within getInstance().

Unfortunately creating a Class<FieldBinder<V>> itself requires an unchecked cast.

Class<FieldBinder<Integer>> binderKlass =
    (Class<FieldBinder<Integer>>) (Class<?>) FieldBinder.class;
BinderAssociator.getInstance(Integer.class, binderKlass);



回答3:


RHSeeger, I got your original question. I found no solution for the problem. What you can try to play with is a MyMap class, which makes the binding as you request. However with this map two problems arise:

  1. As it is declared as MyMap<?>, one cannot add something with a given type to it. That's dummy and I refer you to Java Generics FAQs (see case study 3) for more details.
  2. As map has connection between key and value, one cannot add two independent objects of any type (two <?> refer to different types) because these two types may be not connected.

While playing I have seen some errors, which I could not explain myself. I think, everything goes into the fact (as I mentioned before) that we try to deal with 2-nd level parametrization.

    class FieldBinder<T> {
        static class MyMap<M> extends HashMap<Class<M>, FieldBinder<M>> {
        }
        static final MyMap<?> instanceMap1 = new MyMap<Object>();
        static final Map<Class<?>, FieldBinder<?>> instanceMap2 = new HashMap<Class<?>, FieldBinder<?>>();
        public static <V> void test() {
            Class<V> c1 = null;
            FieldBinder<V> f1 = null;
            Class<?> c2 = null;
            FieldBinder<?> f2 = null;
            instanceMap1.put(c1, f1); // error (see 1)
            instanceMap1.put(c2, f2); // error (see 2)
            instanceMap2.put(c1, f1); // ok
            instanceMap2.put(c2, f2); // ok
            instanceMap2.put(c1, f2); // wish to be an error, but ok
            instanceMap2.put(c2, f1); // wish to be an error, but ok
        }
    }



回答4:


The example you refer tells, how to recover the type (class) of object, while you need to recover the type (class) of parametrization. That is not possible.



来源:https://stackoverflow.com/questions/2208317/generic-map-of-generic-key-values-with-related-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!