开发者

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

开发者 https://www.devze.com 2023-01-16 11:51 出处:网络
I have a method that looks like this public static <T extends MyClass, X extends AnotherClass> List<T> (Class<T> aParameter, X anotherParameter)

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. (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 开发者_如何学Pythonit 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.


I would say no, since due to type erasure, X is actually just Object at runtime. You could try doing something with reflection to test if anotherParameter has getId() and if so, call it.


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
}


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.

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


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. You can't help the "invoke()" part.

0

精彩评论

暂无评论...
验证码 换一张
取 消