2009-10-02 52 views
3

因此,與我一起工作的組已減少了我們爲某些事情鍵入的代碼量。在這種情況下,使用DisplayTag庫顯示列表的Spring網頁。它的做法是使用泛型擴展Controller對象的類,然後爲每個應該使用的頁面創建一個子類。在Java中使用類型擦除

此控制器顯示SystemErrorReport,並將類型定義爲SystemErrorReportCommand

public class SystemErrorReportController extends 
    GenericSearchAndSelectController<SystemErrorReportCommand> { 

的問題是,SystemErrorReportCommand,傳遞作爲一種類型,都需要有其自身的手動聲明在其構造,像這樣:

public SystemErrorReportCommand() 
{ 
    super(SystemErrorReport.class); 
} 

命令對象以後傳遞的東西,需要知道它的顯式類型。沒有在某處手動指定它,它將返回爲GenericCommand,這是我們的另一個類,因爲SystemErrorReportCommand位在編譯時間後會丟失。

我對此並不感到激動,因爲它似乎是我們可以進一步自動化以減少開發人員錯誤的東西。有沒有一種更優雅的方式來做到這一點,或者我堅持這種做法是因爲類型擦除?

回答

1

也許你可以使用像Javassist做一些元編程。

它在Tapestry中用於此目的,請參閱this文章。

3

即使擦除完成後,仍然可以使用反射來檢索Field,Method(包括方法參數)和Class中的通用信息。

例如,可以使用

((ParameterizedType) SystemErrorReportController.class.getGenericSuperType()).getActualTypeArguments[0]; 

仍然檢索SystemErrorReportController的SystemErrorReportCommand,這僅僅是個開始。您需要使用反射api開始使用這些信息,所以如果您不期待這樣的事情,您的設計很可能會受到影響。

這裏是你可以在運行時提取什麼一個小例子:

public abstract class Test<T extends Number> extends ArrayList<Long> implements Comparable<String>, List<Long>{ 
    public List<String> field; 
    public abstract <M> M method(List<T> arg); 

    public static void main(String... args) throws Exception { 
     TypeVariable<Class<Test>> t = Test.class.getTypeParameters()[0]; 
     Class<?> upperBound = (Class<?>) t.getBounds()[0]; 


     System.out.println("Test<" + t + " extends " + upperBound.getName() + ">"); 
     System.out.println("extends " + Test.class.getGenericSuperclass()); 
     System.out.println("implements " + Arrays.toString(Test.class.getGenericInterfaces())); 
     System.out.println("{"); 
     System.out.println(Test.class.getMethods()[1].toGenericString()); 
     System.out.println(Test.class.getFields()[0].toGenericString()); 
     System.out.println("}"); 
    } 
} 

這將輸出:

Test<T extends java.lang.Number> 
extends java.util.ArrayList<java.lang.Long> 
implements [java.lang.Comparable<java.lang.String>, java.util.List<java.lang.Long>] 
{ 
public abstract <M> M Test.method(java.util.List<T>) 
public java.util.List<java.lang.String> Test.field 
} 

我使用toGenericString()方法。然而,這只是一個漂亮的打印方法!有沒有必要解析該字符串:反射API提供所有必要的信息,例如:Field.getGenericType(),Method.getArgumentTypes,...

+0

讓我看一下這個週一。我們已經使用了相當多的思考,我可能需要更具體地處理我的問題,但不要在沒有我面前的例子的情況下進行口誤。 – 2009-10-03 15:23:44

+1

好的,檢查。 這裏的問題是,有這樣的: 類Foo ; - 和 - 類巴茲擴展酒吧; - 和 - 類Zab延伸酒吧; 當一些調用foo 與巴茲(酒吧的子類),所有我能得到的回覆是酒吧,不是巴茲;我失去了子類,只能取回顯式類型。 這是否有意義? – 2009-10-05 20:29:10

+0

是的,不幸的是,這是被刪除的信息。在運行時,Foo類(Foo.class)只有1個實例。所以你只能得到「聲明」泛型類型而不是「實例」泛型類型。這就是「通用化」討論(http://gafter.blogspot.com/2006/11/reified-generics-for-java.html)。不幸的是,這不會成爲Java 7的一部分。 – vdr 2009-10-07 08:33:31