Можно ли получить ссылку на метод Java, чтобы вызвать его позже?

можно ли получить ссылки на методы объекта? Например, я хотел бы иметь метод, который вызывает другие методы в качестве обратных вызовов. Что-то вроде:

public class Whatever
{
  public void myMethod(Method m,Object args[])
  {

  }
}

это возможно?

EDIT: я имел в виду методы объекта. Я так понимаю, это невозможно?

7 ответов


Да, это возможно.

у вас просто есть метод get и вызвать его.

вот пример кода:

$cat InvokeMethod.java  
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

public class InvokeMethod {

    public static void invokeMethod( Method m , Object o ,  Object ... args )  
    throws IllegalAccessException, 
           InvocationTargetException {

        m.invoke( o, args );

    }

    public static void main( String [] args ) 
    throws NoSuchMethodException,
           IllegalAccessException,
           InvocationTargetException {

         SomeObject object = new SomeObject();
         Method method = object.getClass().getDeclaredMethod( "someMethod",  String.class );
         invokeMethod( method, object, "World");

    }
}

class SomeObject {
    public void someMethod( String name ){
        System.out.println( "    Hello " + name );
    }
}
$javac InvokeMethod.java 
$java InvokeMethod
Hello World
$

теперь вопрос в том, что вы пытаетесь сделать? возможно, это лучший способ. Но что касается твоего вопроса, то ответ-да.


Java 7 будет иметь замыкания, которые позволят вам это сделать.

пока это не доступно у вас есть два варианта

  • удерживайте ссылку на интерфейс с известным методом и вызовите это
  • используйте отражение для вызова метода.

противоречит философии дизайна Java. Вы должны создать класс с одним методом и передать ссылку на экземпляр этого.


вот пример того, что требуется для звонка:

public interface Callback {
  public void execute(Object[] args);
}

public class MyCallback implements Callback {
  public void execute(Object args[]) {
    System.out.println(Arrays.asList(args));
  }
}

public class Whatever {
  public void myMethod(Callback callback,Object args[]) {
    callback.execute(args);
  }
}

Если вы передаете экземпляр MyCallback в Whatever.myMethod, он будет печатать все, что вы передаете в качестве аргументов.


Да, вы используете API отражения, например java.lang.Class.getMethods() (и другие подобные методы на Class). Вы вызываете Method объект с помощью Method.invoke().

API отражения не особенно приятно использовать, и он несет штраф за производительность (хотя это гораздо менее существенно, чем раньше), но он выполняет эту работу.


хотя это возможно через отражение, гораздо лучше передать объект и получить к нему доступ через интерфейс, как сортировка в настоящее время работает (передача в компараторе). Привыкание думать и проектировать таким образом-это начало реального понимания программирования ОО.

делать это через ссылки на методы приводит к худшему общему дизайну-но, очевидно, проще для быстрой одноразовой работы Хака. Если вы довольны взломом, просто используйте Groovy где все эти короткие сокращения встроены и имеют значительно сокращенный/упрощенный синтаксис, предназначенный только для быстрого одноразового кода вместо долгосрочного обслуживания.


через отражение вы можете получить доступ к методам класса-см.

http://java.sun.com/docs/books/tutorial/reflect/member/methodInvocation.html

и

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/Method.html

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

 class MethodInvoker{
        private Object o;
        private String methodName;
        public MethodInvoker(Object o, String methodName){
            this.o=o;
            this.methodName=methodName;
        }

        public Object invoke(Object[] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{
            Class[] paramTypes = new Class[args.length];
            for(int i=0;i<paramTypes.length;i++){
                paramTypes[i] = args[i].getClass();
            }
            return o.getClass().getMethod(methodName, paramTypes).invoke(o, args);
        }
    }

будет однако будьте осторожны, так как это не будет работать с нулевыми параметрами.