2008-12-10 30 views
13

是否有可能在Java中反射性地實例化泛型類型?使用描述的技術here我收到錯誤,因爲類令牌不能通用。以下面的例子。我想實例化實現Creator的Creator的一些子類。實際的類名稱作爲命令行參數傳入。這個想法是能夠在運行時指定Creator的實現。有沒有另一種方法來完成我在這裏要做的事情?可以反思性地實例化java中的泛型類型嗎?

public interface Creator<T> { 
    T create(); 
} 
public class StringCreator implements Creator<String> { 
    public String create() { return new String(); } 
} 
public class FancyStringCreator implements Creator<String> { 
    public String create() { return new StringBuffer().toString(); } 
} 
public static void main(String[] args) throws Exception { 
    Class<?> someClass = Class.forName(args[0]); 
    /*ERROR*/Class<? extends Creator<String>> creatorClass = someClass.asSubclass(Creator.class); 
    Constructor<? extends Creator<String>> creatorCtor = creatorClass.getConstructor((Class<?>[]) null); 
    Creator<String> creator = creatorCtor.newInstance((Object[]) null); 
} 

編輯:我喜歡馬庫斯的方法,因爲它是最簡單實用的方法,沒有規避整體的泛型。我可以在我的情況中使用它,因爲我可以指定傳遞的類必須是StringCreator的子類。但是正如Ericson所指出的那樣,通用信息仍然存在於類型級別,而不是在運行級別,所以仍然可以反思性地檢查給定的類是否實現了正確的泛型類型。

回答

7

通用信息在運行時丟失。沒有運行時等效的Creator < String> .class。你可以創建創造者和StringCreator之間的類型,修正了泛型類型:

public interface Creator<T> { 
     T create(); 
} 
public interface StringCreator extends Creator<String> { } 
public class StringCreatorImpl implements StringCreator { 
     public String create() { return new String(); } 
} 
public class FancyStringCreator implements StringCreator { 
     public String create() { return new StringBuffer().toString(); } 
} 
public static void main(String[] args) throws Exception { 
     Class<?> someClass = Class.forName(args[0]); 
     Class<? extends StringCreator> creatorClass = someClass.asSubclass(StringCreator.class); 
     Constructor<? extends StringCreator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null); 
     Creator<String> creator = creatorCtor.newInstance((Object[]) null); 
} 

但是,當然,你失去了一點靈活性,因爲你不能使用下面的創建者類:

public class AnotherCreator implements Creator<String> { 
    public String create() { return ""; } 
} 
+0

並非所有通用信息在運行時都會丟失;即使沒有創建另一個界面,也有足夠的時間檢查必要的類型信息。只是沒有足夠的信息讓編譯器推斷正確性。 – erickson 2008-12-10 19:48:48

3

你不需要那條線。你也不需要構造函數,因爲你只是使用默認構造函數。只需直接實例化類:

public static void main(String[] args) throws Exception { 
     Class<?> someClass = Class.forName(args[0]); 
     Creator<String> creator = (Creator<String>) someClass.newInstance(); 
} 

如果你堅持,你將只能得到一半了:

public static void main(String[] args) throws Exception { 
    Class<?> someClass = Class.forName(args[0]); 
    Class<? extends Creator> creatorClass = someClass.asSubclass(Creator.class); 
    Constructor<? extends Creator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null); 
    Creator<String> creator = (Creator<String>) creatorCtor.newInstance((Object[]) null); 
} 
+0

claz.newInstance ()和ctor.newInstance()在發生錯誤時的行爲不完全相同。類的newInstance方法較舊,與其他反射式「方法」調用不一致。 – erickson 2008-12-10 16:33:34

-1

不明白爲什麼你在這裏使用泛型。

使用反射建議的一般用途,但想必你會打電話給create在某些時候和結果分配給String對象的實例化,否則爲什麼要使用仿製藥,以控制返回類型。

但是,如果你寫了下面執行造物主的:

public class IntegerCreator implements Creator<Integer> 
{ 
    public Integer create() 
    { 
    ... 
    } 
} 

並通過它與調用create和分配結果的時候你會得到一個ClassCastException一個說法。

4

這將做你正在做的事情,同時提供類型安全。沒有辦法避免未經檢查的警告,但這裏完成的類型檢查證明了它的抑制。

public static void main(String[] args) 
    throws Exception 
    { 
    Class<? extends Creator<String>> clz = load(argv[0], String.class); 
    Constructor<? extends Creator<String>> ctor = clz.getConstructor(); 
    Creator<String> creator = ctor.newInstance(); 
    System.out.println(creator.create()); 
    } 

    public static <T> Class<? extends Creator<T>> load(String fqcn, Class<T> type) 
    throws ClassNotFoundException 
    { 
    Class<?> any = Class.forName(fqcn); 
    for (Class<?> clz = any; clz != null; clz = clz.getSuperclass()) { 
     for (Object ifc : clz.getGenericInterfaces()) { 
     if (ifc instanceof ParameterizedType) { 
      ParameterizedType pType = (ParameterizedType) ifc; 
      if (Creator.class.equals(pType.getRawType())) { 
      if (!pType.getActualTypeArguments()[0].equals(type)) 
       throw new ClassCastException("Class implements " + pType); 
      /* We've done the necessary checks to show that this is safe. */ 
      @SuppressWarnings("unchecked") 
      Class<? extends Creator<T>> creator = (Class<? extends Creator<T>>) any; 
      return creator; 
      } 
     } 
     } 
    } 
    throw new ClassCastException(fqcn + " does not implement Creator<String>"); 
    } 

你要堅持的主要限制是,在分級中的類必須指定類型參數。例如class MyCreator implements Creator<String>。您不能與class GenericCreator<T> implements Creator<T>一起使用。

當前不處理,你創建一個新的接口interface StringCreatorIfc extends Creator<String>,並有一個類實現了有效的情況下。它可以被強化來做到這一點,但我會把它作爲對那些傾向者的練習。