Общие методы Java, приведенные к типу параметра во время выполнения, это возможно? - PullRequest
4 голосов
/ 15 сентября 2010

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

 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.

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

Ответы [ 5 ]

5 голосов
/ 15 сентября 2010

Можете ли вы модифицировать производные классы?Если это так, вы можете определить интерфейс для этого (синтаксис может быть неправильным):

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 голосов
/ 15 сентября 2010

Я бы сказал нет, так как из-за стирания типа, X на самом деле просто Object во время выполнения. Вы можете попробовать сделать что-то с отражением, чтобы проверить, есть ли у другого параметра getId(), и если это так, вызвать его.

2 голосов
/ 15 сентября 2010

Вы можете использовать отражение для вызова метода во время выполнения, если он существует.

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 голосов
/ 15 сентября 2010

Концепция приведения чего-либо во время выполнения на самом деле не имеет смысла, поскольку у вас есть экземпляр, и он может сказать вам, какой это класс.Вам нужно будет использовать отражение, например, с помощью 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;
}
1 голос
/ 15 сентября 2010

Как уже говорили другие, отражение - это единственное практическое решение для этого, но я бы немного улучшил это, кэшируя метаданные отражения (возможно, карту с ключом class + methodName), так как эта часть отражения не ' т совсем дешево. Вы не можете помочь "invoke ()" часть.

...