Pet*_*rey 23 java lambda bytecode java-8
如果你有像这样的匿名类
Predicate<String> isEmpty = new Predicate<String>() {
public boolean test(String t) {
return t.isEmpty();
}
};
Run Code Online (Sandbox Code Playgroud)
传递引用的库isEmpty可以检查字节代码以查看它的作用并可能对其进行操作.有没有办法可以为lambdas做到这一点?
Predicate<String> isEmpty = String::isEmpty;
Run Code Online (Sandbox Code Playgroud)
例如,假设有这个代码和字节码
public class Main {
public static void test(Predicate<String> tester) {
System.out.println("tester.getClass()= " + tester.getClass());
System.out.println("tester.getClass().getClassLoader()="+ tester.getClass().getClassLoader());
}
public static void main(String... args) {
Predicate<String> isEmpty = String::isEmpty;
test(isEmpty);
}
}
$ javap -cp . -c -private Main.class
Compiled from "Main.java"
public class Main {
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void test(java.util.function.Predicate<java.lang.String>);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: ldc #5 // String tester.getClass()=
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_0
16: invokevirtual #7 // Method java/lang/Object.getClass:()Ljava/lang/Class;
19: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
22: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
25: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
31: new #3 // class java/lang/StringBuilder
34: dup
35: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
38: ldc #11 // String tester.getClass().getClassLoader()=
40: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: aload_0
44: invokevirtual #7 // Method java/lang/Object.getClass:()Ljava/lang/Class;
47: invokevirtual #12 // Method java/lang/Class.getClassLoader:()Ljava/lang/ClassLoader;
50: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
53: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
56: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
59: return
public static void main(java.lang.String...);
Code:
0: invokedynamic #13, 0 // InvokeDynamic #0:test:()Ljava/util/function/Predicate;
5: astore_1
6: aload_1
7: invokestatic #14 // Method test:(Ljava/util/function/Predicate;)V
10: return
}
Run Code Online (Sandbox Code Playgroud)
有了一个参考tester的test我怎么觉得这方法被调用?
Bri*_*etz 12
如果您只想查看字节码:
javap -c -p -v classfile
^disassemble
^private methods
^verbose, including constant pool and bootstrap methods attribute
Run Code Online (Sandbox Code Playgroud)
但是如果你想在运行时尝试这样做,那么你很幸运(在设计上,我们没有像Expression Trees这样的东西),正如另一个答案所暗示的那样.
简单的答案是:你做不到.Brian Goetz就此事有一个相关的答案.为了实现lambda表达式,javac创建了一个INVOKEDYNAMIC将调用委托给LambdaMetafactorybootstrap方法的指令.对于OpenJDK,此引导方法然后使用ASM在运行时创建所需接口的实现.
在该test方法中,retreived实例tester属于此ASM生成的类,因此您无需读取类文件以查找Predicate表示的方法.在一般情况下,如何将lambda表达式映射到接口实现的确切决定留给了运行时环境,这使得您的问题变得更加困难.找出lambda表达式所代表的方法的唯一方法是读取其创建的字节代码,即为main您的示例解释方法.