如何在不使用方法字符串名称的情况下在Java中获取Method对象

时间:2012-03-25 21:37:24

标签: java reflection

我正在寻找从方法中获取Method对象的便捷解决方法。想法:

Method fooMethod = getMethod( new MyObject().foo() ) // returns method "foo" in MyObject

显而易见的方法是将方法的名称用作字符串:

Method fooMethod = MyObject.class.getMethod("foo")

但是我想避免这种情况,因为如果我重命名foo()代码将停止工作,或者我在所有使用它的地方重命名字符串。

用例是我想使用类似于ProperyChangeListeners的东西,但是那些依赖于方法名称作为字符串。我想使用实际的方法(安全)而不依赖于字符串。

我可以用什么方法以重命名安全的方式获取方法?

更新: 我想找到一个不依赖IDE功能的纯java解决方案

8 个答案:

答案 0 :(得分:11)

Java 8方法引用对于此非常理想 - 棘手的部分是获取底层方法,因为方法引用语法本身会导致不透明的lambda对象。

经过一番搜索后发现了这个:

http://benjiweber.co.uk/blog/2013/12/28/typesafe-database-interaction-with-java-8/

巧妙的技巧 - 在记录方法名称的代理对象上调用方法。没试过,但看起来很有希望。

答案 1 :(得分:9)

在您的方法调用中: 方法me =(new MethodNameHelper(){})。getMethod();

/**
 * Proper use of this class is
 *     Method me = (new MethodNameHelper(){}).getMethod();
 * the anonymous class allows easy access to the method name of the enclosing scope.
 */
public class MethodNameHelper {
  public Method getMethod() {
    return this.getClass().getEnclosingMethod();
  }
}

答案 2 :(得分:7)

实际上有一个库可以做到这一点:

Jodd MethRef - 强类型方法名称引用

https://jodd.org/ref/methref.html

Methref<Str> m = Methref.on(Str.class);  // create Methref tool

// example #1
m.to().boo();
m.ref();                               // returns String: 'boo'

答案 3 :(得分:4)

我们发布了可用于捕获方法的小型库de.cronn:reflection-util

示例:

class MyClass {

    public void myMethod() {
    }

}

Method method = ClassUtils.getVoidMethod(MyClass.class, MyClass::myMethod);
System.out.println(method.getName()); // prints "myMethod"

实现细节:使用ByteBuddy创建MyClass的代理子类,并捕获对该方法的调用以检索其名称。 ClassUtils缓存信息,以便我们不需要在每次调用时创建新代理。

答案 4 :(得分:3)

您可能想要使用注释。您可以为要检索的每个方法创建自定义注释,并使用反射从对象中提取该方法。

您可以安全地重命名该方法,您的代码也可以使用。

如果您希望能够检索许多方法,那么只使用一个带有字符串值的注释,该值将根据方法更改,然后您的反射代码将查找具有该字符串值的注释。只要保留注释的字符串值相同,您仍然可以重命名方法。

答案 5 :(得分:1)

最安全的做法是使用具有重构功能的IDE,该功能足以识别和替换String方法名称。来自JetBrains的IntelliJ做到了 - 我只是向自己证明了这一点。

答案 6 :(得分:-1)

您可以使用IDE重构,它也会关注所有字符串的出现。

除了名称之外,您不能使用反射来引用方法。

答案 7 :(得分:-1)

通过使用反射,你只是放弃了编译时的安全性。

而是考虑这里是否真的需要反思。您可以使用Runnable表示您的方法,例如:

Runnable foo = new Runnable() {
    @Override
    public void run() {
        new MyObject().foo();
    }
}

...

foo.run();

或者,如果您需要使用返回类型表示方法,请查看Callable - 甚至更好,Guava的Function