2013-10-27 111 views
0

我無法弄清楚用泛型做到這一點的正確方法。我有一個類,Foo,它有一個通用的(Foo<class>)。然後我想要有一張Map<String, Foo>的地圖。現在,我可以做到這一點,並將Foo<String>添加爲一個地圖項目,並將Foo<Integer>添加爲另一個地圖項目。然而,當我使用地圖的get方法,我只是得到一個Foo背部和類型可以不再被推斷,所以,如果我做的:Java與泛型混淆

String s = map.get("StringFoo") 

我得到一個編譯錯誤,必須做到:

String s =(String)map.get(「StringFoo」)

什麼是一種好的模式來做這樣的事情來避免投射,因爲這就是泛型所要做的。我可能能夠做到像Map<String, Foo<?>>這樣的事情,但那是做到這一點的方式嗎?

我的代碼的詳細信息如下,這可以放在一個目錄中,javac *.java && java Main將運行它。

我在Foo.java一個通用的Java類,

public class Foo<T> 
{ 
    T value; 

    public T getValue() 
    { 
     return this.value; 
    } 

    public void setValue(T t) 
    { 
     this.value = t; 
    } 
} 

現在,我已經在Main.java以下測試類:

import java.util.Map; 
import java.util.HashMap; 

public class Main 
{ 
    public static void main(String[] a) 
     { 
      Foo<String> fooStr = new Foo<String>(); 
      fooStr.setValue("TEST 123"); 

      Foo<Integer> fooInt = new Foo<Integer>(); 
      fooInt.setValue(314159); 

      Map<String, Foo> mapOfFoo = new HashMap<String, Foo>(); 

      mapOfFoo.put("Strings", fooStr); 
      mapOfFoo.put("Integer", fooInt); 

      System.out.println("All set"); 

      String s = mapOfFoo.get("Strings").getValue(); 

      System.out.println("Got: " + s); 

     } 
} 

當我編譯此,我得到的以下錯誤:

Main.java:21: error: incompatible types 
      String s = mapOfFoo.get("Strings").getValue(); 
                ^
    required: String 
    found: Object 
1 error 

當我這樣做是Main.java,它的工作原理:

import java.util.Map; 
import java.util.HashMap; 

public class Main 
{ 
    public static void main(String[] a) 
     { 
      Foo<String> fooStr = new Foo<String>(); 
      fooStr.setValue("TEST 123"); 

      Foo<Integer> fooInt = new Foo<Integer>(); 
      fooInt.setValue(314159); 

      Map<String, Foo> mapOfFoo = new HashMap<String, Foo>(); 

      mapOfFoo.put("Strings", fooStr); 
      mapOfFoo.put("Integer", fooInt); 

      System.out.println("All set"); 

      String s = (String)mapOfFoo.get("Strings").getValue(); 

      System.out.println("Got: " + s); 

     } 
} 

我不確定最佳做法是什麼樣的。有沒有人有什麼建議?

+0

好的,我的代碼在開始時變得糟糕透露,因爲它剝離了我的>和<標籤中的一些,但示例代碼應該得到跨越的點 – mikeb

+0

只需使用四空間縮進;普通尖括號可以正常工作。 – chrylis

回答

3

這種構造在Java中實際上並不常見,問題是通用參數是僅編譯時功能,並且該映射檢索是僅用於運行時功能,因此無法編譯器能夠理解你的規則,而不是在某處發出警告。

實現這種結構最安全的方式是通過一個包裝類,它在邏輯上確保類型安全,你所要做的就是在吸氣劑上拋出SuppressWarnings("unchecked")

public class FooMapper { 

    private Map<Class<?>, Foo<?>> fooMap = new HashMap<>(); 

    public <T> void setFoo(Class<T> clazz, Foo<T> foo) { 
    fooMap.put(clazz, foo); 
    } 

    @SuppressWarnings("unchecked") 
    public <T> Foo<T> getFoo(Class<T> clazz) { 
    return (Foo<T>) fooMap.get(clazz); 
    } 

} 

此包裝保證你永遠不能把錯誤類型的Foo用錯Class對象,所以投絕不可能失敗「選中」。

+0

這看起來像我想要做的,但我得到2編譯錯誤:'FooMapper.java:5:錯誤:無效的方法聲明;需要返回類型 public setFoo(Class clazz,Foo foo){ ^ FooMapper.java:10:error:invalid method declaration;返回類型 public getFoo(類 clazz){ ^' – mikeb

+0

啊,這是我的一個小小的疏忽。現在修復 – torquestomp

4

您似乎在您的Map聲明和構造中使用非通用Foo。相反,這樣的:

Map<String, Foo> mapOfFoo = new HashMap<String, Foo>(); 

應該是這樣的:

Map<String, Foo<String>> mapOfFoo = new HashMap<String, Foo<String>>(); 

然後,你將不必強制轉換爲字符串 - 在首位使用泛型的原因之一,而Foo#getValue()將返回字符串明確。

+0

那麼,那就是失敗的目的。如果您查看代碼,我會將'Foo '和'Foo '添加到'Map ',這就是我遇到問題的地方。 – mikeb

+2

@ user1022260:啊​​,所以我明白了。那麼你的設計就被打破了,你不應該創造出一個必須施展的構造。如果你絕對需要這個,那麼再使用一次間接尋址,並創建一個使用Type參數的Map。 –