繁体   English   中英

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

[英]How to get Method object in Java without using method string names

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

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

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

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

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

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

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

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

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

经过一番搜索,找到了这个:

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

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

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

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'

在您的方法调用中: Method 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();
  }
}

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

例子:

class MyClass {

    public void myMethod() {
    }

}

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

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

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

您可以安全地重命名该方法,并且您的代码将起作用。

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

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

您可以使用 IDE 重构来处理所有字符串的出现。

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

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

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

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

...

foo.run();

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM