【问题标题】:Is it possible to get a reference to a Java method to invoke it later?是否有可能获得对 Java 方法的引用以便稍后调用它?
【发布时间】:2010-01-06 21:19:00
【问题描述】:

是否可以获得对对象方法的引用?例如,我想要一个调用其他方法作为回调的方法。比如:

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

  }
}

这可能吗?

编辑:我的意思是对象的方法。我认为这是不可能的?

【问题讨论】:

  • 你的意思是“类的方法”,而不是“对象的方法”,对吧?
  • @skaffman:对象的类的方法。那个怎么样?这是一个重要的区别:如果您有一个匿名类实例,则不能通过名称引用该类,只能通过在实例上调用getClass。通过使用反射,您可以访问通常无法通过基接口/类/枚举访问的其他方法。 :-P

标签: java methods


【解决方案1】:

是的,这是可能的。

您只需获取方法并调用它。

这里有一些示例代码:

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

现在的问题是,你想做什么?也许是更好的方法。但至于你的问题,答案是肯定的。

【讨论】:

    【解决方案2】:

    Java 7 将有闭包,可以让你做到这一点。

    在这可用之前,您有两个选择

    • 保持对具有已知方法的接口的引用并调用它
    • 使用反射调用方法。

    【讨论】:

    • Java 7 也会有方法句柄,更直接。 :-P
    • C# 风格的委托呢?我们随时都能拿到吗?
    • 闭包是否通过了 Java 7?
    • @cb160: Java7 可能有闭包,目前还不确定。不过,在这一点上看起来很有希望。
    • Java 1.1 有(详细的)闭包。
    【解决方案3】:

    与 Java 的设计理念背道而驰。您应该创建一个单一方法类并传递对该实例的引用。

    【讨论】:

    • 如果我们谈论的是类的设置器,则不会扩展。 10 个 setter + 10 个 getter = 20 个对象以类型安全的方式引用它们不是很好^^ 所以你最终会得到非类型安全的字符串和反射(就像在许多框架中一样)
    【解决方案4】:

    以下是回调所需内容的示例:

    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 的实例传递给 What.myMethod,它将打印您作为参数传递的任何内容。

    【讨论】:

      【解决方案5】:

      虽然可以通过反射实现,但更好的办法是传递一个对象并通过接口访问它,就像排序当前的工作方式一样(传入一个比较器)。养成以这种方式思考和设计的习惯是真正理解 OO 编程的开始。

      通过方法引用来做这件事会导致更糟糕的整体设计——但对于快速的一次性 hack 工作来说显然更容易。如果您对 hack 感到满意,只需使用 Groovy,因为所有这些快捷方式都内置,并且语法大大减少/简化,专为快速一次性代码而不是长期维护而设计。

      【讨论】:

        【解决方案6】:

        是的,您使用反射 API,例如 java.lang.Class.getMethods()(以及 Class 上的其他类似方法)。您使用Method.invoke() 调用Method 对象。

        反射 API 使用起来并不是特别好,而且它会带来性能损失(尽管这比以前要小得多),但它确实可以完成工作。

        【讨论】:

          【解决方案7】:

          通过反射,您可以访问类的方法 - 请参阅

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

          不过要小心,因为这不适用于任何空参数。

          【讨论】:

            猜你喜欢
            • 2012-07-29
            • 2020-05-04
            • 2018-11-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-02-15
            • 1970-01-01
            • 2014-03-07
            相关资源
            最近更新 更多