在Java中使用Type Erasure

时间:2009-10-02 14:34:20

标签: java generics type-erasure

因此,我使用的组减少了我们为某些事情键入的代码量。在这种情况下,Spring网页使用DisplayTag库显示列表。它的完成方式是使用泛型扩展Controller对象的类,然后是它应该处理的每个页面的子类。

此控制器显示SystemErrorReport,并将类型定义为SystemErrorReportCommand

public class SystemErrorReportController extends
    GenericSearchAndSelectController<SystemErrorReportCommand> {

问题是SystemErrorReportCommand作为一个类型传递,需要在其构造函数中有一个自己的手动声明,如下所示:

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

稍后将命令对象传递给需要知道其显式类型的东西。如果没有在某处手动指定它,它会返回GenericCommand,这是我们的另一个类,因为SystemErrorReportCommand位在编译时丢失了。

我对此并不感到兴奋,因为看起来我们可以进一步自动化以减少开发人员错误。有没有更优雅的方法来做到这一点,还是我因为类型擦除而坚持这个?

3 个答案:

答案 0 :(得分:4)

与广泛接受的内容相反,可以避免很少知道的类型擦除,这意味着被叫方确实能够知道在呼叫期间使用了哪些通用参数。

请看看: Using TypeTokens to retrieve generic parameters

由于

答案 1 :(得分:3)

即使在擦除完成后,仍然可以从:Field,Method(包括方法参数)和使用反射的类中检索通用信息。

例如,可以使用

从SystemErrorReportController检索SystemErrorReportCommand。
((ParameterizedType) SystemErrorReportController.class.getGenericSuperType()).getActualTypeArguments[0];

尽管如此,这只是一个开始。你需要开始使用反射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()方法。然而,这只是一种漂亮的打印方法!无需解析该String:reflection api提供了所有必要的信息,例如:Field.getGenericType()Method.getArgumentTypes,...

答案 2 :(得分:1)

也许你可以使用类似Javassist的东西来做一些元编程。

为了这个目的,它在Tapestry中使用,请参阅this文章。