字节码分析-方法引用
源码
package java.bytecode;
import java.util.ArrayList;
import java.util.List;
/**
* 方法引用示例 - 演示Java 8方法引用
*/
public class MethodReferenceExample {
// 静态方法引用示例
public void staticMethodReferenceExample() {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.forEach(System.out::println);
}
// 实例方法引用示例
public void instanceMethodReferenceExample() {
List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.forEach(String::toUpperCase);
}
// 构造方法引用示例
public void constructorReferenceExample() {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.stream()
.map(Integer::new)
.forEach(System.out::println);
}
}
结构化反解析
(完整javap输出请查看:java/bytecode/MethodReferenceExample_javap.txt)
关键部分:
public void staticMethodReferenceExample();
Code:
26: aload_1
27: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
30: dup
31: invokestatic #26 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
34: pop
35: invokedynamic #32, 0 // InvokeDynamic #0:accept:(Ljava/io/PrintStream;)Ljava/util/function/Consumer;
40: invokeinterface #36, 2 // InterfaceMethod java/util/List.forEach:(Ljava/util/function/Consumer;)V
BootstrapMethods:
0: #107 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(...)
Method arguments:
#77 (Ljava/lang/Object;)V
#79 invokevirtual java/io/PrintStream.println:(Ljava/lang/String;)V
#86 (Ljava/lang/String;)V
1: #107 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(...)
Method arguments:
#77 (Ljava/lang/Object;)V
#87 invokevirtual java/lang/String.toUpperCase:()Ljava/lang/String;
#86 (Ljava/lang/String;)V
2: #107 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(...)
Method arguments:
#94 (Ljava/lang/Object;)Ljava/lang/Object;
#95 newinvokespecial java/lang/Integer."<init>":(Ljava/lang/String;)V
#100 (Ljava/lang/String;)Ljava/lang/Integer;
详细说明
方法引用类型
方法引用也使用invokedynamic指令实现,通过LambdaMetafactory在运行时生成实现类。
1. 静态方法引用
System.out::println - 引用静态方法或实例方法
#79 invokevirtual java/io/PrintStream.println:(Ljava/lang/String;)V
2. 实例方法引用
String::toUpperCase - 引用实例方法
#87 invokevirtual java/lang/String.toUpperCase:()Ljava/lang/String;
3. 构造方法引用
Integer::new - 引用构造方法
#95 newinvokespecial java/lang/Integer."<init>":(Ljava/lang/String;)V
MethodHandle
方法引用通过MethodHandle表示要引用的方法:
invokevirtual- 实例方法invokestatic- 静态方法newinvokespecial- 构造方法
实现机制
方法引用的实现机制与Lambda表达式相同:
1. 使用invokedynamic指令
2. 引导方法为LambdaMetafactory.metafactory
3. 通过MethodHandle引用目标方法
4. 运行时动态生成实现类
与Lambda的区别
- Lambda:需要生成Lambda方法体
- 方法引用:直接引用已存在的方法,不需要生成额外的方法
性能优势
方法引用通常比Lambda表达式更高效,因为:
- 不需要生成Lambda方法
- 直接引用目标方法
- JVM可以更好地优化