代码之家  ›  专栏  ›  技术社区  ›  John

在运行时Java中获取方法引用的名称是否可能(如何)?[复制品]

  •  1
  • John  · 技术社区  · 6 年前

    最近我使用了很多方法引用和lambda,我想知道在运行时是否可以打印以筛选lambda IE的名称的源代码,只是出于调试的原因。我在getname()中调用getClass()可能会使用反射,但我找不到一个方法来查找原始源引用的名称。

    我有一个功能接口,比如:

    @FunctionalInterface
    public interface FooInterface {
        // function etc etc irrelevant
        public void method();
    
        public default String getName() {
            // returns the name of the method reference which this is used to define
        }
    }
    

    然后假设我希望测试运行接口,并将功能接口的源文件打印到屏幕上。

    public static void doStuff(FooInterface f) {
        // prints the lambda name that is used to create f
        System.out.println(f.getName());
    
        // runs the method itself
        f.method();
    }
    

    如果我这样做:

    doStuff(Foo::aMethodReference);
    

    它应该在屏幕上打印类似“amethodReference”的内容,这样我就可以知道运行时运行的是哪些方法,以什么顺序等等。

    我很怀疑这是可能的,考虑到lambda不是一个物体,但嘿,我想可能有一个解决办法。此外,Eclipse调试工具只是说它是一个lambda,没有任何其他信息,lambda是否保留了这些信息?还是在运行时全部丢失?

    干杯。(如果有什么不同的话,我使用的是JDK 11)

    1 回复  |  直到 6 年前
        1
  •  1
  •   fps    6 年前

    正如您所说,您只需要将其用于调试目的,这里有一个技巧(即一个肮脏的黑客)可以让您做您想要的事情。

    首先,您的功能接口必须 Serializable :

    @FunctionalInterface
    public interface FooInterface extends Serializable {
    
        void method();
    }
    

    现在,你可以用这个了 无文件证明、依赖于内部实施和 极其危险的 用于打印有关方法引用的某些信息的代码 有针对性的 对你 FooInterface 功能接口:

    @FunctionalInterface
    public interface FooInterface extends Serializable {
    
        void method();
    
        default String getName() {
            try {
                Method writeReplace = this.getClass().getDeclaredMethod("writeReplace");
                writeReplace.setAccessible(true);
                SerializedLambda sl = (SerializedLambda) writeReplace.invoke(this);
                return sl.getImplClass() + "::" + sl.getImplMethodName();
            } catch (Exception e) {
                return null;
            }
        }
    }
    

    当您调用此方法时:

    doStuff(Foo::aMethodReference);
    

    您将看到以下输出:

    package/to/the/class/Foo::aMethodReference
    

    注1:我在 this article by Peter Lawrey .

    注2:我已经用 openjdk version "11" 2018-09-25 并与 java version "1.8.0_192" .