2010-02-05 50 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