У меня есть метод, который выглядит так
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.
Можно ли применить это динамически? к любому другому параметру во время выполнения?.
Ответ 1 · рейтинг 5 · gpeche
Можно ли модифицировать производные классы? Если это так, вы можете определить интерфейс для этого (синтаксис может быть неправильным):
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(), доступный непосредственно внутри вашего метода.
Ответ 3 · рейтинг 2 · Stephen P
Вы можете использовать отражение для вызова метода во время выполнения, если он существует.
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 · рейтинг 2 · Jon Freedman
Концепция приведения чего-то во время выполнения на самом деле не имеет смысла, поскольку у вас есть экземпляр, и он может сказать вам, какой это класс. Вам нужно будет использовать отражение, например, используя 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;
}
Ответ 5 · рейтинг 1 · David M. Karr
Как уже говорили другие, отражение является единственным практическим решением этой проблемы, но я бы немного улучшил его, кэшируя метаданные отражения (возможно, карту с ключом class+methodName), поскольку эта часть отражения не совсем дешевая. . Вы не можете помочь части "invoke()".