Java泛型方法在运行时强制转换为参数类型,是否可能?

时间:2010-09-15 15:35:39

标签: java runtime types generics casting

我有一个看起来像这样的方法

 public static <T extends MyClass, X extends AnotherClass> List<T> (Class<T> aParameter, X anotherParameter)

现在,如果AnotherClass是一个没有定义getId的抽象类,但扩展此接口的每个类都有。 (不要问我为什么设计这个为什么,我没有设计抽象类,我不允许改变它。)

我该怎么做呢

anotherParameter.getId();

我知道我必须把它投射到课堂上,但是我必须对每个可能的课程进行一次检查,然后再进行投射。

所以我知道我有类似的东西:

if (anotherParameter instanceof SomeClass)
    ((SomeClass)anotherParameter).getId();  //This looks bad.

是否可以动态地将其转换为运行时的其他参数?

5 个答案:

答案 0 :(得分:5)

你能修改派生类吗?如果是这样,你可以为此定义一个接口(语法可能错误):

public interface WithId {
    void getId();
}
...
public class MyDerivedClass1 extends AnotherClass implements WithId {
...
}
...
public class MyDerivedClass2 extends AnotherClass implements WithId {
...
}

然后,在你的方法中执行:

...
if (anotherParameter instanceof WithId) {
 WithId withId = (WithId) anotherParameter;
 withId.getId();
}
...

如果您可以更改方法的签名,也许您可​​以指定intersection type

public static <T extends MyClass, X extends AnotherClass & WithId> List<T> myMethod(Class<T> aParameter, X anotherParameter)

然后您可以直接在方法中使用getId()

答案 1 :(得分:3)

我会说不,因为由于类型擦除,X在运行时实际上只是Object。您可以尝试使用反射来测试另一个参数是否有getId(),如果是,请调用它。

答案 2 :(得分:2)

在运行时投射内容的概念确实没有意义,因为你有一个实例,它可以告诉你它是什么类。您将需要使用反射,例如使用Introspector类。

private Integer getId(final X anotherParameter) {
    final BeanInfo beanInfo = Introspector.getBeanInfo(anotherParameter.getClass());
    for (MethodDescriptor methodDescriptor : beanInfo.getMethodDescriptors()) {
        final Method method = methodDescriptor.getMethod();
        if ("getId".equals(method.getName())
                && method.getParameterTypes().length == 0) {
            return (Integer) method.invoke(anotherParameter);
        }
    }
    return null;
}

答案 3 :(得分:2)

如果存在,可以使用反射在运行时调用该方法。

try {
    Method m = anotherParameter.getClass().getMethod("getId", null);
    Object result = m.invoke(anotherParameter, null);
}
catch (NoSuchMethodException e) {
   // ... and several other exceptions need to be caught
}

答案 4 :(得分:1)

正如其他人所说,反射是唯一可行的解​​决方案,但我会通过缓存反射元数据(可能是由类+ methodName键入的地图)来增强这一点,因为反射的那部分是'完全便宜。你无法帮助“调用()”部分。