2011-06-01 77 views
8

當結果是泛型時,我該如何調用Class.forName()?通常我可以使用asSubclass(),但是在這裏我唯一能看到的方法就是演員陣容,當其他所有內容都很好地與泛型一起輸入時,我會發現其中的一些缺陷&。Typesafe forName class loading

的情況是這樣的:

沒有與具有main()一個入口點主類一個.jar。它需要一個類名的選項(和其他一些,在這裏不相關)。給出的類實現Callable<Integer>。這個班加載後,啓動&。

這裏是什麼,我需要一個例子:

Class<? extends Callable<Integer>> clazz = (Class<? extends Callable<Integer>>) Class.forName(options.valueOf(className)).asSubclass(Callable.class); 

有什麼辦法來擺脫鑄造的?

使用SE6。

回答

10

首先,你可能要一個完整的通用Class

Class<Callable<Integer>> classCI = ...; 

那麼Java類型系統具有

Class<? extends Callable<Integer>> clazz =  
    Class.forName(options.valueOf(className)) 
    .asSubclass(classCI); 

沒有問題,我們怎樣才能獲得classCI?我們可以通過選中投

Class<Callable<Integer>> classCI = (Class<Callable<Integer>>)Callable.class; 

這本身就是不安全的欺騙。必須有外力才能確保className確實是Callable<Integer>。例如,如果它是Callable<String>,程序將毫無問題地運行所有演員陣列,並且只有在Integer call()被調用時纔會爆炸,並且錯誤消息將非常具有誤導性。

這是確定的,如果鑄造不能靜態地分析成功:

Object o = ...; 
String s1 = (String)o; // may fail, no javac warning 
String s2 = String.class.cast(o); // may fail, no javac warning 

只要當鑄鋼在運行時失敗,異常立即拋出。

爲類型的安全,我們必須主動檢查泛型類型的className

@SuppressWarning("unchecked") 
Class<? Callable<Integer>> getClass(String className) 
{ 
    Class clazz = Class.forName(className); 
    via reflection, check generic super interfaces of clazz 
    if there's no Callable<Integer> super interface 
     throw "className is not a Callable<Integer>" 

    // we have *checked*, the following cast is safe 
    return (Class<? Callable<Integer>>)clazz; 
} 

,我們有理由打壓「未選中」在這裏,因爲實現檢查以確保如果className沒有按並不代表實施Callable<Integer>的課程,它立即在那裏引發異常。我們的演員是「檢查」,並且該程序是類型安全的。

+0

+1:omg,我真的很想適應泛型,所以我可以理解這裏發生了什麼。 – Rekin 2011-06-01 08:40:13

+0

哇,很好的答案。謝謝,接受。 :) – TC1 2011-06-01 15:07:15

+0

僅供參考,鑄造類> classCI =(Class >)Callable.class由於某種原因不起作用。無論如何,因爲我通過反思檢查了Callable ,這並不是什麼大不了的事情,如果你想編輯這個,只需要考慮一下。 – TC1 2011-06-03 07:39:41