Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Общие методы Java приводятся к типу параметра во время выполнения, возможно ли это?

Автор вопроса: Oscar GomezОтветов: 5

У меня есть метод, который выглядит так

 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.

Можно ли применить это динамически? к любому другому параметру во время выполнения?.

javatypesgenericscastingruntime

Ответы

Ответ 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(), доступный непосредственно внутри вашего метода.

Ответ 2 · рейтинг 3 · takteek

Я бы сказал нет, так как из-за стирания типа X на самом деле просто Object во время выполнения. Вы можете попробовать сделать что-то с отражением, чтобы проверить, имеет ли другой параметр 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()".

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы