避免Java类型擦除

时间:2011-12-09 23:16:12

标签: java templates generics generic-programming type-erasure

有没有办法可以避免类型擦除并获得对类型参数的访问权?

public class Foo<T extends Enum<?> & Bar> {
    public Foo() {
        // access the template class here?
        // i.e. :
        baz(T.class); // obviously doesn't work
    }

    private void baz(Class<T> qux) { 
        // do stuff like
        T[] constants = qux.getEnumConstants();
        ...
    } 
}

我需要了解T,并用它做事。是否可能,如果是这样,如何在没有传递构造函数中的类或参数之外的任何地方的情况下完成

编辑:这个问题的主要目的是找出类型擦除周围是否有任何实用的方式

5 个答案:

答案 0 :(得分:5)

AFACT,有关于类型擦除的 no 实用方法,因为你不能要求运行时无法访问的东西。当然假设您同意对实现Bar接口的每个枚举进行子类化通用类是一个实际的工作。

enum Test implements Bar {
    ONE, TWO
}

class Foo<T> extends FooAbstract<Test> {
    public Foo() {
        ParameterizedType genericSuperclass =
                (ParameterizedType) getClass().getGenericSuperclass();
        baz((Class<T>) genericSuperclass.getActualTypeArguments()[0]);
    }

    private void baz(Class<T> qux) {
        T[] constants = qux.getEnumConstants();
        System.out.println(Arrays.toString(constants)); // print [ONE, TWO]
    }
}

interface Bar {
}

class FooAbstract<T extends Enum<?> & Bar> {
}

答案 1 :(得分:2)

如果您愿意/能够将类令牌交给构造函数:

public Foo(Class<T> clazz) {
    baz(clazz);
}

private void baz(Class<T> qux) {
    // ...
}

这样,您可以使用Class.newInstance()生成类型为T的对象,尝试使用Class.cast()等将任意对象强制转换为T.

你打算用baz()做什么?

答案 2 :(得分:1)

正如pholser在他的回答中指出的那样,实现这一目标的唯一方法是传入代表Class类型的T对象。这是因为Type Erasure因为T.class在运行时被删除,所以T之类的东西是不可能的。

您似乎拒绝传入Class对象,但这是使用方法getEnumConstants()的唯一方法。这是一个自包含的例子:

public class Foo<T extends Enum<?> & Bar> {

   final Class<T> clazz;

   public Foo(Class<T> clazz) {

      this.clazz = clazz;
   }

   public void baz() {

      T[] constants = clazz.getEnumConstants();

      System.out.println(Arrays.toString(constants));
   }

   public static void main(String[] args) {

       new Foo<MyEnum>(MyEnum.class).baz(); //prints "[A, B, C, D]"
   }
}

public interface Bar { }

public enum MyEnum implements Bar { A, B, C, D; }

答案 3 :(得分:1)

使用Neil Gafter提出的超类型令牌,并由像guice这样的库用于此目的。

请参阅http://gafter.blogspot.com/2006/12/super-type-tokens.html了解原始描述,并查看CA无线电生活工作实施的guice源。

还有另一个q,其中有一个内联工作示例的答案How can I pass a Class as parameter and return a generic collection in Java?

答案 4 :(得分:0)

在某些情况下,您可以使用Richard Gomes建议的解决方法。 创建匿名类的实例时,可以使用类型参数类信息。

class A<T>
{
    A()
    {
        java.lang.reflect.ParameterizedType parameterizedType = (java.lang.reflect.ParameterizedType)  (this.getClass().getGenericSuperclass());
        System.out.println(parameterizedType.getActualTypeArguments()[0]);
    }
}

public class Example {
 public static void main(String[] args) {
     A<String> anonymous = new A<String>() {};  // prints java.lang.String
}
}

请注意,以这种方式创建的多个实例将具有不同的匿名类,如果这是一个问题,您可能需要具有基于clone的createNew()函数的类A_String_Factory来替换对new的调用。