2010-02-05 62 views
14

我正在尝试创建一个通用类型,它保留已创建供以后使用的自身版本的映射。实际上,每个类型只有一个实例是单例模式。我到目前为止的代码是:通用键/值与相关类型的通用映射

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 - > FieldBinder)。 IDE警告返回声明只会加强这一想法。

有没有更好的方法来处理这个问题?

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

回答

14

您的实施是正确的。有这样做(如果有这样的事情是在代码中“更好”,这是另一个问题。)

小幅修正的没有“更好”的方式:

  • <V extends Object>相当于V这是更简洁
  • Class<? extends Object>相当于Class<?>这是更简洁
  • 可以使用@SuppressWarnings("unchecked")注释要告诉你的编译器,中投是安全
1

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

+0

假设我明白你在说什么,那么这根本就不是我正在做的。我想要告诉编译器“这是一张从'Class '到'FieldBinder '的地图,其中两个?必须相同。因此,当我使用χ= xyz键拔出某些东西时,我可以安全地将值赋给?= xyz,因为编译器可以限制我只以这种方式放置东西。这些都是编译时的信息,看起来好像编译器不能处理。 – RHSeeger 2010-02-05 18:26:58

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

RHSeeger,我把你原来的问题。我找不到解决问题的办法。你可以尝试使用的是一个MyMap类,它根据你的请求进行绑定。然而与此映射两个问题就出来了:

  1. 因为它被声明为MyMap<?>,不能与给定类型,将其添加的东西。这是假的,我将你引用Java Generics FAQs(参见案例研究3)了解更多详情。
  2. 由于映射关键字和值之间有连接,因此不能添加两个任意类型的独立对象(两个<?>指的是不同类型),因为这两种类型可能没有连接。

在玩游戏时,我看到一些错误,我无法解释自己。我认为,事实上(正如我之前提到的),我们试图处理2级参数化。

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

感谢您的详细解答。对于Java泛型没有完成我现在想要完成的任务,这个事实很好掌握,你的回答有助于巩固这一点。我想我真的很希望看到的是能够说 .. .. static final Map ,FieldBinder > instanceMap2 = new HashMap ,FieldBinder >( ); .... 其中表示“任何类型”,但将该类型绑定到可以稍后使用的变量。 – RHSeeger 2010-02-06 19:43:21