Java 8 - 如何访问被绑定为lambda的对象和方法

wal*_*ros 6 java reflection lambda java-8

在Java中,您可以"捕获"对象的"方法调用"作为Runnable,如下例所示.

之后,有权访问Runnable的这个实例,是否可以实际访问"捕获"对象和被调用方法的方法参数(如果可能,这可能需要通过反射来完成).

例如:

class SomePrintingClass {
  public void print(String myText) {
    System.out.println(myText);

  }
}


public class HowToAccess {
  public static void main(String[] args) throws Exception {
    final String myText = "How to access this?";

    final SomePrintingClass printer = new SomePrintingClass();

    Runnable r = () -> printer.print(myText); // capture as Runnable

    inspect(r);
  }


  private static void inspect(Runnable runnable) {
    // I have reference only to runnable... can I access "printer" here

  }


}
Run Code Online (Sandbox Code Playgroud)

是否可以在"inspect"方法中访问(可能通过反射)"printer"对象和作为参数传递的"myText"?

Jor*_*nee 8

这是可能的,因为捕获的引用被转换为runnable的字段(与所有匿名类一样).但名称不一致.

我通过测试发现你需要创建myTextfinal,否则它将被视为编译时常量和内联(并且不能作为字段访问):

private static void inspect(Runnable runnable) throws Exception {       
    for(Field f : runnable.getClass().getDeclaredFields()) {
        f.setAccessible(true);
        System.out.println("name: " + f.getName());
        Object o = f.get(runnable);
        System.out.println("value: " + o);
        System.out.println("class: " + o.getClass());
        System.out.println();
    }
}
Run Code Online (Sandbox Code Playgroud)

打印:

name: arg$1
value: test.SomePrintingClass@1fb3ebeb
class: class test.SomePrintingClass

name: arg$2
value: How to access this?
class: class java.lang.String
Run Code Online (Sandbox Code Playgroud)

  • 尽管有可能做到这一点,但应该注意的是,这依赖于特定于实现的行为(未由规范定义),因此它可能会在不同的JDK版本中中断. (6认同)
  • 好吧,要么是非"最终",要么不立即初始化,例如`final String myText; myText ="如何访问它?";`不是编译时常量(虽然这不是禁止内联,但是当前编译器不会发生这种情况,而对于编译时常量,内联是必需的). (2认同)
  • 除了依赖于特定于实现的行为之外,正如Stuart reMarks所说,显然(但显然不是)您正在访问您无法控制的类的私有状态,这应该是您的大红色警告表明你做错了什么,也许你应该寻找另一种解决方案.(它也有可能闯入人们的房子并窃取东西,但仅仅因为你可以,并不意味着你应该.) (2认同)