2010-01-06 8 views
7

¿Es posible obtener referencias a los métodos de un objeto? Por ejemplo, me gustaría tener un método que invoca otros métodos como devoluciones de llamada. Algo como:¿Es posible obtener una referencia a un método Java para invocarlo más tarde?

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

    } 
} 

¿Esto es posible?

EDIT: I significaba métodos de un objeto. ¿Lo tomo, no es posible?

+0

¿Quiere decir "métodos de una clase", no "métodos de un objeto", ¿verdad? – skaffman

+0

@skaffman: métodos de clase de un objeto. ¿Qué hay sobre eso? Esta es una distinción importante: si tiene una instancia de clase anónima, no puede hacer referencia a la clase por su nombre, solo mediante la llamada 'getClass' en la instancia. Al usar la reflexión, puede acceder a otros métodos a los que normalmente no puede acceder a través de la interfaz base/clase/enum. :-P –

Respuesta

6

Sí, es posible.

Solo tiene que obtener el método e invocarlo.

He aquí algunos ejemplos de código:

$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 
$ 

Ahora la pregunta es, ¿qué estás tratando de hacer? quizás son mejores formas. Pero en cuanto a su pregunta, la respuesta es SÍ.

4

Java 7 tendrá cierres que le permiten hacer esto.

Hasta que esto está disponible, tiene dos opciones

  • contener una referencia a una interfaz con un método conocido en la llamada que
  • y
  • utilizar la reflexión para llamar al método.
+1

Java 7 también tendrá identificadores de método, que son incluso más directos. :-P –

+0

¿Qué pasa con delegados de estilo C#? ¿Estamos recibiendo esos en cualquier momento? –

+0

¿Los cierres lograron pasar por Java 7? – OscarRyz

1

Sí, utiliza la API de reflexión, por ejemplo java.lang.Class.getMethods() (y otros métodos similares en Class). Invoca un objeto Method utilizando Method.invoke().

La API de reflexión no es especialmente agradable de usar, y se acompaña de una reducción del rendimiento (aunque esto es mucho menos importante de lo que solía ser), pero hace el trabajo.

3

Funciona de forma contraria a la filosofía de diseño de Java. Se supone que debes crear una clase de método único y pasar una referencia a una instancia de eso.

+0

No escala si estamos hablando de establecedores de una clase. 10 setter + 10 getter = 20 objetos para referenciarlos de una manera segura no pueden ser buenos ^^ Así que terminas con cadenas y reflectivos que no son seguros (como en muchos frameworks) – Tarion

+0

No digo que sea algo bueno. ¡Ve C# con sus delegados! –

3

He aquí un ejemplo de lo que se requiere para una devolución de llamada:

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); 
    } 
} 

Si entrega una instancia de MyCallback en Whatever.myMethod, se imprimirá lo que sea que vaya a entregar como los argumentos.

0

través de la reflexión se puede obtener acceso a los métodos de una clase - ver

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

y

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

Sin embargo, usted tiene que pasar en una instancia de esa clase, así como los argumentos. Se puede crear una clase contenedora simple, sin embargo, algo así como

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); 
     } 
    } 

tener cuidado, sin embargo, ya que esto no iba a funcionar con cualquier parámetro nulos.

1

Aunque es posible a través de la reflexión, la apuesta es mucho mejor que pasar un objeto y acceder a ella a través de una interfaz de la forma de clasificación actualmente funciona (pasando de un comparador). Adquirir el hábito de pensar y diseñar de esta manera es el comienzo de realmente entender la programación OO.

Hacerlo a través de referencias método conduce hacia el diseño global peor - pero evidentemente es más fácil para un único trabajo de corte rápido. Si está contento con hackear simplemente use Groovy en lugar de todos los atajos incorporados y tenga una sintaxis simplificada/simplificada, diseñada para un código desechable rápido en lugar de un mantenimiento a largo plazo.

Cuestiones relacionadas