2015-03-31 49 views
2

民間,在通用類中添加泛型成員變量

是否有任何簡單的方法在非泛型類中添加泛型類。

基本上緩存管理器將具有使用適當的泛型實現的Cache類的映射。

但是在下面的類中,我們返回(getCache方法)通過get方法緩存它需要在調用方顯式轉換如何避免它。

例如

public class CacheManager { 
    private Map<String, Cache<?,?>> cacheMap = new HashMap<String, Cache<?,?>>(); 
    public Cache<?,?> getCache(String cacheName) { 
     return cacheMap.get(cacheName); 
    } 

    public void addCache(String cacheName,Cache<?,?> cache) { 
     cacheMap.put(cacheName, cache); 
    } 
} 
+0

沒有未經檢查的強制轉換(在這種特殊情況下將是類型安全的IMO),沒有辦法做到這一點。您可以通過向通配符添加邊界來添加更多類型安全。 – 2015-03-31 11:56:35

+0

是否有通配符類型,因爲單個CacheManager實例將存儲許多不同類型的緩存? (也就是說,爲什麼它不是CacheManager ?) – 2015-03-31 12:07:45

+0

Rohit你可以舉例說明如何向通配符添加更多邊界。我現在正在做明確的轉換(Cache )cacheManager.getCache(「test」)Erik你是對的我有不同的緩存,所以我不能在泛型中使用CacheManager。請提出更好的建議。 – user1927808 2015-03-31 12:28:40

回答

0

簡短回答:沒有(據我所知)。

這裏的問題是,你所做的事在Java中根本不是類型安全的。看看這個例子:

import java.util.*; 

class ClassCast { 
    public static void main(String[] args) { 
     HashMap<String, Pair<?, ?>> map = new HashMap<>(); 

     map.put("test", new Pair<String, Integer>("Hello", 5)); 

     Pair<Double, Double> pair = (Pair<Double, Double>) map.get("test"); 
    } 
} 

class Pair<T,V> { 
    T a; 
    V b; 

    Pair(T a, V b) { 
     this.a = a; 
     this.b = b; 
    } 
} 

你可能會認爲這裏ClassCastException,但它編譯和運行完全正常。原因在於Pair<String, Integer>Pair<Double, Double>的實際類別實際上只是Pair(類型擦除之後)。

爲了獲得類型安全,您必須實現「Typesafe heterogeneous container pattern」(由Josh Bloch在Effective Java中詳細解釋)。簡而言之,您必須將類型參數包含在地圖的關鍵字中。根據您的需要,您可能可以直接使用類作爲密鑰,否則可能必須創建關鍵對象。

實現示例:

public class CacheManager { 
    private Map<MultiKey, Cache<?,?>> cacheMap = new HashMap<>(); 

    @SuppressWarnings("unchecked") 
    public <T,V> Cache<T,V> get(String name, Class<T> t, Class<V> v) { 
     // Type-safe since types are encoded in key(i.e. map will not 
     // return something with the wrong type), and key is type-checked 
     // on insertion. 
     return (Cache<T,V>) cacheMap.get(new MultiKey(name, t, v)); 
    } 

    public <T,V> void put(String name, Class<T> t, Class<V> v, Cache<T,V> cache) { 
     cacheMap.put(new MultiKey(name, t, v), cache); 
    } 

    class MultiKey { 
     Object[] keys; 
     Integer hash = null; 

     MultiKey(Object... keys) { 
      this.keys = keys; 
     } 

     @Override 
     public int hashCode() { 
      if (hash == null) hash = Arrays.hashCode(keys); 
      return hash; 

     } 

     @Override 
     public boolean equals(Object o) { 
      if (o == null || !(o instanceof MultiKey)) return false; 
      return Arrays.equals(keys, ((MultiKey) o).keys); 
     } 
    } 
} 

用法示例:

CacheManager mng = new CacheManager(); 

mng.addCache("SI", String.class, Integer.class, new Cache<String, Integer>()); 

Cache<String, Integer> cache = mng.getCache("SI", String.class, Integer.class); 

System.out.println(cache); 

這不是很漂亮,但它實際上是類型安全的。儘管它可以根據實際情況進行改進,所以您不應該按原樣使用此代碼。例如,如果您可以從緩存對象中獲取類型,則不需要addCache中的類參數。