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

4
我有一个类似于这样的方法
 public static <T extends MyClass, X extends AnotherClass> List<T> (Class<T> aParameter, X anotherParameter)

现在,如果AnotherClass是一个抽象类,它没有定义getId方法,但是每个继承该接口的类都有。 (不要问我为什么会这样设计,我没有设计这个抽象类,也不被允许更改它)。

那么我该如何做到这一点呢?

anotherParameter.getId();

我知道我必须将其转换为类,但然后我必须对每个可能的类进行一个instanceof检查,然后再进行转换。
所以现在我有这样的东西:
if (anotherParameter instanceof SomeClass)
    ((SomeClass)anotherParameter).getId();  //This looks bad.

在运行时,是否可以动态地将其转换为另一个参数(即anotherParameter)?

5个回答

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();
}
...

如果你可以更改方法的签名,也许可以指定一个交集类型

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

然后你就可以直接在方法内使用getId()了。


请注意,您可以不实现WithId接口,而是:1)编写一个抽象类AnotherClassWithId,提供抽象方法getId();2)让派生类扩展该类;3)将方法参数anotherParameter的类型设置为AnotherClassWithId。这样做会更简单,需要对代码进行的更改也会更少,但基本思路是相同的。 - gpeche

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

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
}

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;
}

1

正如其他人在这里所说,反射是这个问题的唯一实际解决方案,但我会通过缓存反射元数据(例如一个按类+方法名为键的映射)来增强它,因为反射的这一部分并不完全便宜。你无法避免 "invoke()" 部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接