是否有任何hack在运行时知道实例的泛型的实际具体类?

时间:2015-12-14 15:51:46

标签: java generics inheritance reflection java-8

我希望找到一个hack来推断运行时另一个实例的var的实际通用实例,不带

  • 更改我需要的方法签名(添加辅助参数Class<T>,显而易见的方式)
  • 以硬编码方式instanceof所有可能的子类型

    MyInterface<? extends Number> myInterface = whateverReturnsWildcardDoubleInterface();
    Class<?> type = inferInstanceType(myInterface);
    assert type == Double.class;  
    
    /** This is the method that represents the code I am looking for  with the conrete signature**/
    public <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
        return T.class; //Concrete T (can or cannot be the very Number)  
    }
    

理想情况下,当T为特定子类型Integer时,它应返回Double,Double ..和T当数字时为数字

我检查过反射,几个&#34; TypeResolver&#34; /&#34; GenericResolver&#34; libs(作为Spring中的一个或Github中的其他人),但我无法找到破解它的方法。

编辑:我得出的结论是,他只有可行的方法才能通过堆栈跟踪进行某种非常复杂的反射,直到在实例化中传递类型的实际线< / p>

EDIT2:我知道这很愚蠢...但我只是在我的界面上添加T getT()方法解决了这个问题,所以我可以return myInterface.getT().getClass() < / p>

2 个答案:

答案 0 :(得分:4)

免责声明:此解决方案是根据我对您的设置的理解而定制的 hack ,即一个具有单个类型参数的通用接口,多个类,而不是它们本身是通用的,直接单独实现这一个接口,并且不直接或间接地实现其他通用接口。

假设以上所有都是正确的,有一种相对简单的方法来攻击解决方案:调用getClass().getGenericInterfaces()会返回一个Type对象,该对象提供实例化通用接口的实际类型

interface MyInterface<T extends Number> {
    T getVal();
}
class DoubleImpl implements MyInterface<Double> {
    public Double getVal() {return 42.42; }
}
...
public static void main (String[] args) throws java.lang.Exception {
    MyInterface<? extends Number> x = new DoubleImpl();
    Type[] ifs = x.getClass().getGenericInterfaces();

    System.out.println(ifs.length);
    for (Type c : ifs) {
        System.out.println(c);
        Type[] tps = ((ParameterizedType)c).getActualTypeArguments();
        for (Object tp : tps) {
            System.out.println("===="+tp); // <<== This produces class java.lang.Double
        }
    }
}

Demo.

答案 1 :(得分:-4)

正如assylias指出的那样,Java的擦除将使这些信息在运行时不可用 - 因此需要进行黑客攻击。

假设myInterfaceT的getter,如MyInterface.getValue():T(或黑客会添加它),你可以做这样的事情(忽略这种可能性) getValue()可以返回null):

public <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
    return myInterface.getValue().getClass()
}

以下是完整的实施

public class Q34271256 {

  public static interface MyInterface<T> {
    T getValue();
  }

  public static class MyDoubleClass implements MyInterface<Double> {
    private final Double value;
    public MyDoubleClass(Double value) {
      this.value = value;
    }
    @Override
    public Double getValue() {
      return value;
    }
  }

  public static class MyIntegerClass implements MyInterface<Integer> {
    private final Integer value;
    public MyIntegerClass(Integer value) {
      this.value = value;
    }
    @Override
    public Integer getValue() {
      return value;
    }
  }

  @SuppressWarnings("unchecked")
  public static <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
    Number value = myInterface.getValue();
    if (value == null) return null;
    return (Class<T>)value.getClass();
  }

  public static void main(String...args) {
    List<MyInterface<? extends Number>> list = Arrays.asList(
        new MyDoubleClass(1.1),
        new MyIntegerClass(5)
    );
    for (MyInterface<? extends Number> myInterface : list) {
      Class<?> type = inferInstanceType(myInterface);
      System.out.printf("%s inferred type is %s\n",
          myInterface.getClass().getName(),
          type.getName());
    }
  }
}

输出应该如下所示:

MyDoubleClass inferred type is java.lang.Double
MyIntegerClass inferred type is java.lang.Integer