具有相关类型的通用键/值的通用映射

时间:2010-02-05 15:40:22

标签: java generics collections

我正在尝试创建一个泛型类型,该类型保留了为以后使用而创建的自身版本的映射。实际上,它是一个单例模式,每种类型都有一个实例。我到目前为止的代码是:

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);
    }
}

然而,我仍然不确定我“做得对”。感觉我应该能够指定集合是(Class - &gt; FieldBinder)。 IDE警告返回语句的事实只会加强这种想法。

有没有更好的方法来解决这个问题?

注意:This question似乎非常密切相关,但距离足够远,我无法弄清楚如何将信息应用于我自己的问题。

4 个答案:

答案 0 :(得分:15)

您的实施是正确的。没有“更好”的方法(如果在代码中有这样的东西“更好”,这是另一个问题..)

次要修正:

  • <V extends Object>相当于V,不那么详细
  • Class<? extends Object>相当于Class<?>,不那么详细
  • 您可以使用@SuppressWarnings("unchecked")注释告诉编译器演员阵容是安全的

答案 1 :(得分:3)

如果没有一个未经检查的演员,我认为不能做到。你需要类似于Haskell的existential types,这是Java没有的。

您可以让客户端执行未经检查的强制转换......

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));
}

现在,如果客户端将Class<FieldBinder<V>>传递给getInstance()方法,则可以避免getInstance()内未经检查的广告投放。

不幸的是,创建一个Class<FieldBinder<V>>本身需要一个未选中的强制转换。

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

答案 2 :(得分:3)

RHSeeger,我收到了你原来的问题。我找不到解决问题的方法。您可以尝试使用的是MyMap类,它可以根据您的要求进行绑定。然而,有了这张地图,就会出现两个问题:

  1. 由于它被声明为MyMap<?>,因此无法向其添加具有给定类型的内容。这是虚拟的,我将您推荐给Java Generics FAQs(参见案例研究3)了解更多详情。
  2. 由于地图在键和值之间有连接,因此无法添加任意类型的两个独立对象(两个<?>引用不同类型),因为这两种类型可能未连接。
  3. 在玩的时候,我看到了一些错误,我无法解释。我认为,一切都进入事实(正如我之前提到的),我们试图处理第二级参数化。

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

答案 3 :(得分:1)

您引用的示例告诉我,如何恢复对象的类型(类),同时需要恢复参数化的类型(类)。这是不可能的。