2009-10-02 59 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