我有一个看起来像这样的方法
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.
是否可以动态地将其转换为运行时的其他参数?
答案 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键入的地图)来增强这一点,因为反射的那部分是'完全便宜。你无法帮助“调用()”部分。