简体   繁体   English

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

[英]Java generic methods cast to parameter type at runtime, is it possible?

I have a method that looks like this 我有一个看起来像这样的方法

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

Now if AnotherClass is an abstract class that does NOT Have getId defined, but every single class that extends this interface does. 现在,如果AnotherClass是一个没有定义getId的抽象类,但扩展此接口的每个类都有。 (Don't ask me why it is designed this why, I did not design the abstract class, and I am not allowed to change it). (不要问我为什么设计这个为什么,我没有设计抽象类,我不允许改变它)。

How can I do something like this 我怎么能做这样的事情

anotherParameter.getId();

I know I have to cast it to the class, but then i have to do an instanceof check for every possible class and then cast it. 我知道我必须将它投射到课堂上,但是我必须对每个可能的课程进行一次检查,然后再进行投射。

So right know i have something like: 所以我知道我有类似的东西:

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

Is it possible to cast this dynamically?, to whatever anotherParameter is at runtime?. 是否可以动态地将其转换为运行时的其他参数?

Can you modify derived classes? 你能修改派生类吗? If so, you could define an interface for this (syntax maybe wrong): 如果是这样,你可以为此定义一个接口(语法可能错误):

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

and then, inside your method do: 然后,在你的方法里面做:

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

If you can change your method's signature, maybe you can specify an intersection type : 如果您可以更改方法的签名,也许您可​​以指定交集类型

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

and then you would have getId() available directly inside your method. 然后你可以直接在你的方法中使用getId()

I would say no, since due to type erasure, X is actually just Object at runtime. 我会说不,因为由于类型擦除, X实际上只是运行时的Object You could try doing something with reflection to test if anotherParameter has getId() and if so, call it. 您可以尝试使用反射来测试另一个参数是否具有getId() ,如果是,则调用它。

The concept of casting something at runtime doens't really make sense, as you have an instance, and it can tell you what class it is. 在运行时投射某些东西的概念确实没有意义,因为你有一个实例,它可以告诉你它是什么类。 You will need to use reflection, for example using the Introspector class. 您将需要使用反射,例如使用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;
}

You could use reflection to invoke the method at runtime if it exists. 您可以使用反射在运行时调用该方法(如果存在)。

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
}

As others here have said, reflection is the only practical solution to this, but I would enhance this a little bit by caching the reflection metadata (perhaps a map keyed by the class+methodName), as that part of reflection isn't completely cheap. 正如其他人所说的那样,反射是唯一可行的解​​决方案,但我会通过缓存反射元数据(可能是由类+ methodName键入的地图)来增强这一点,因为反射的那部分不是很便宜。 You can't help the "invoke()" part. 你无法帮助“invoke()”部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM