我希望找到一个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>
答案 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
}
}
}
答案 1 :(得分:-4)
正如assylias指出的那样,Java的擦除将使这些信息在运行时不可用 - 因此需要进行黑客攻击。
假设myInterface
有T
的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