Я хотел бы иметь возможность вызывать «getProgram» для объектов, у которых есть этот метод, не зная, к какому классу они принадлежат. Я знаю, что здесь мне следует использовать интерфейс, но я работаю с чужим кодом и не могу перепроектировать классы, с которыми работаю. Я думал, что BeanUtils.getProperty может мне помочь, но, похоже, он возвращает только строки. Есть ли что-то вроде Beanutils.getProperty, которое вернет литой объект? Или другой, более разумный способ работы с двумя похожими классами, которые не имеют общего интерфейса? спасибо, -Морган
получение свойства java bean неизвестного класса
Ответы (7)
Предположительно, у вас есть конечное число классов, реализующих этот метод, и вы можете ссылаться на них напрямую. Так что вам не нужно отражение. Отражение зло.
Скажем, у вас есть набор классов с методом:
public class LibA { public Program getProgram() { return program; } ... };
public class LibB { public Program getProgram() { return program; } ... };
...
Тогда вам просто нужны пары instanceof/cast. Вы можете поместить это в метод, чтобы вам нужно было сделать это только один раз.
public static Program getProgram(Object obj) {
if (obj instanceof LibA) {
return ((LibA)obj).getProgram();
} else if (obj instanceof LibB) {
return ((LibB)obj).getProgram();
} else {
throw new IllegalArgumentException(obj+" doesn't have a known getProgram");
// Or an appropriate application exception.
}
}
В качестве альтернативы вы можете использовать адаптер:
public interface ProgramContainer {
Program getProgram();
...
}
public class LibAContainer implements ProgramContainer {
private final LibA libA;
public LibAContainer(LibA libA) {
this.libA = libA;
}
public Program getProgram() {
return libA.getProgram();
}
...
}
Используйте PropertyUtils (из apache commons-beanutils) вместо BeanUtils.
У него есть метод getProperty(Object bean, String name), который возвращает Object вместо String.
Дополнительную информацию см. в JavaDoc.
Просто используйте для этого отражение... в следующем примере показано, как это сделать на объектах, не имеющих общего интерфейса.
public static void main(String[] args) throws Exception {
doSomething(new A());
doSomething(new B());
}
private static void doSomething(Object object) throws Exception {
Method m = object.getClass().getMethod("doSomething", (Class[])null);
m.invoke(object, (Object[])null);
}
private static class A {
public void doSomething() {
System.out.println("I'm doing it already!");
}
}
private static class B {
public void doSomething() {
System.out.println("I'm doing it too!");
}
}
См. Reflection API:
Используйте Class.getMethod() (или getMethods()), чтобы найти подходящий метод и вызвать его.
Довольно простое решение: используйте делегирование, которое реализует интерфейс:
interface GetProgram
{
String getProgram ();
}
class AWrapper implements GetProgram
{
A a;
public AWrapper (A a) { this.a = a;
String getProgram () { return a.getProgram(); }
}
Теперь вы можете использовать интерфейс в своем коде, не касаясь исходных классов.
Недостаток: это не работает, если вы A созданы где-то за пределами вашей досягаемости. Лучше всего работает, если A создается один раз под вашим контролем, и вы можете сразу же обернуть его.
Чуть более короткая версия, если у вас Java 5+
public static void main(String[] args) throws Exception {
System.out.println(invoke("toString", new A());
System.out.println(invoke("toString", new B());
}
private static <R> R invoke(Object object, String methodName) throws Exception {
return (R) object.getClass().getMethod(methodName).invoke(object);
}
java.beans.Expression сделает это , если метод доступен в конкретном классе получателя.
public static void main(String[] args) throws Exception {
new Expression(new A(), "doSomething", null).getValue();
new Expression(new B(), "doSomething", null).getValue();
}
public static class A {
public void doSomething() {
System.out.println("I'm doing it already!");
}
}
public static class B {
public void doSomething() {
System.out.println("I'm doing it too!");
}
}