2012-10-29 83 views
2

如何創建一個泛型類,它從創建/注入此泛型類時放置的泛型類型參數中獲取類類型? 我的目標是指定例如MyGeneric<User>,然後通用類應該能夠在所有方法調用中使用User類。而不必在附加的泛型構造函數中明確提供User.class僅通過類型參數創建泛型類?

喜歡的東西:

class MyGeneric<T> { 
    public MyGeneric() { 
     someService.create(Class<T>, someString); 
    } 
} 

class Usage { 
    @Inject 
    MyGeneric<User> myuser; 
} 

這是怎麼propertly做了什麼?

+0

爲什麼?這不會允許MyGeneric使用T的方法。MyGeneric只能使用T的上界方法。 – ignis

回答

0

你可以做的是在超類中編寫實例化代碼,然後對每個特定的泛型類型進行擴展(在子類中需要很少或沒有代碼,但是子類是必需的,因爲它們是避免類型的唯一方法擦除):

abstract class MyGeneric<T> { 

    private T instance; 

    public MyGeneric(String str) { 
     // grab the actual class represented by 'T' 
     // this only works for subclasses of MyGeneric<T>, not for MyGeneric itself ! 
     Class<T> genericType = (Class<T>) ((ParameterizedType)getClass().getGenericSuperclass()) 
       .getActualTypeArguments()[0]; 
     try { 
      // instantiate that class with the provided parameter 
      instance = genericType.getConstructor(String.class).newInstance(str); 
     } catch (Exception e) { 
      throw new IllegalArgumentException(e); 
     } 
    } 
} 

class MyUser extends MyGeneric<User> { 
    public MyUser() { 
     // provide the string to use for instantiating users... 
     super("userStr"); 
    } 
} 

class User { /*...*/ } 

編輯:由通用類abstract強制子類的用法。

它也可以用匿名類等一起使用:

new MyGeneric<User>("..string...") {}

我覺得這是最接近您最初的目標,你可以得到...

2

由於運行時間type erasure,無法執行此操作。

通常的方法是(如你所說)將Class<T>的實例 - 稱爲type token - 傳遞給構造函數。鑑於你的代碼模式,你堅持使用這種方法。

0

這是有點棘手,但與例如TypeLiteral從吉斯,你可以做這樣的事情:

public class ReiHashMap<K,V> extends HashMap<K,V> { 

    private final TypeLiteral<K> keyTL; 

    public ReiHashMap(TypeLit<K> keyTL) { 
     this.keyTL = keyTL; 
    } 

    @Override 
    public V get(Object o) { 
     if (!keyTL.getRawType().isAssignableFrom(o.getClass())) { 
      throw new IllegalArgumentException("object " + o + " (class "+ o.getClass() +")ist not of type " + keyTL); 
     } 
     return super.get(o); 
    } 
    ... 

這是一個擴展,可以檢查在運行時獲取的參數的類型包含HashMap。