假设我们有以下类:
final class Impl implements Gateway3 {
private final Sensor sensor1;
private final Sensor sensor2;
private final Sensor sensor3;
private final Alarm alarm;
public Impl(Sensor sensor1, Sensor sensor2, Sensor sensor3, Alarm alarm) {
this.sensor1 = sensor1;
this.sensor2 = sensor2;
this.sensor3 = sensor3;
this.alarm = alarm;
}
@Override
public Temperature averageTemp() {
final Temperature temp1 = sensor1.temperature();
final Temperature temp2 = sensor2.temperature();
final Temperature temp3 = sensor3.temperature();
final Average tempAvg = new Average.Impl(temp1, temp2, temp3);
final Temperature result = tempAvg.result();
return result;
}
@Override
public void poll() {
final Temperature avgTemp = this.averageTemp();
this.alarm.trigger(avgTemp);
}
这个类广泛使用局部变量并且它们都是最终的。
如果我们查看为averageTemp
方法生成的字节码,我们将看到以下字节码:
0: aload_0
1: getfield #2 // Field sensor1:Lru/mera/avral/script/bytecode/demo/Sensor;
4: invokeinterface #6, 1 // InterfaceMethod ru/mera/avral/script/bytecode/demo/Sensor.temperature:()Lru/mera/avral/script/bytecode/demo/Temperature;
9: astore_1
10: aload_0
11: getfield #3 // Field sensor2:Lru/mera/avral/script/bytecode/demo/Sensor;
14: invokeinterface #6, 1 // InterfaceMethod ru/mera/avral/script/bytecode/demo/Sensor.temperature:()Lru/mera/avral/script/bytecode/demo/Temperature;
19: astore_2
20: aload_0
21: getfield #4 // Field sensor3:Lru/mera/avral/script/bytecode/demo/Sensor;
24: invokeinterface #6, 1 // InterfaceMethod ru/mera/avral/script/bytecode/demo/Sensor.temperature:()Lru/mera/avral/script/bytecode/demo/Temperature;
29: astore_3
30: new #7 // class ru/mera/avral/script/bytecode/demo/Average$Impl
33: dup
34: aload_1
35: aload_2
36: aload_3
37: invokespecial #8 // Method ru/mera/avral/script/bytecode/demo/Average$Impl."<init>":(Lru/mera/avral/script/bytecode/demo/Temperature;Lru/mera/avral/script/bytecode/demo/Temperature;Lru/mera/avral/script/bytecode/demo/Temperature;)V
40: astore 4
42: aload 4
44: invokeinterface #9, 1 // InterfaceMethod ru/mera/avral/script/bytecode/demo/Average.result:()Lru/mera/avral/script/bytecode/demo/Temperature;
49: astore 5
51: aload 5
53: areturn
有很多存储操作码。
现在,假设使用字节码生成库,我为相同的方法生成了以下字节码:
0: new #18 // class ru/mera/avral/script/bytecode/demo/Average$Impl
3: dup
4: aload_0
5: getfield #20 // Field sensor1:Lru/mera/avral/script/bytecode/demo/Sensor;
8: invokeinterface #25, 1 // InterfaceMethod ru/mera/avral/script/bytecode/demo/Sensor.temperature:()Lru/mera/avral/script/bytecode/demo/Temperature;
13: aload_0
14: getfield #27 // Field sensor2:Lru/mera/avral/script/bytecode/demo/Sensor;
17: invokeinterface #25, 1 // InterfaceMethod ru/mera/avral/script/bytecode/demo/Sensor.temperature:()Lru/mera/avral/script/bytecode/demo/Temperature;
22: aload_0
23: getfield #29 // Field sensor3:Lru/mera/avral/script/bytecode/demo/Sensor;
26: invokeinterface #25, 1 // InterfaceMethod ru/mera/avral/script/bytecode/demo/Sensor.temperature:()Lru/mera/avral/script/bytecode/demo/Temperature;
31: invokespecial #33 // Method ru/mera/avral/script/bytecode/demo/Average$Impl."<init>":(Lru/mera/avral/script/bytecode/demo/Temperature;Lru/mera/avral/script/bytecode/demo/Temperature;Lru/mera/avral/script/bytecode/demo/Temperature;)V
34: invokevirtual #36 // Method ru/mera/avral/script/bytecode/demo/Average$Impl.result:()Lru/mera/avral/script/bytecode/demo/Temperature;
37: areturn
从语义上讲,与旧方法相比,这种新方法实现具有相同的含义 - 它仍然从三个传感器获取温度值,对它们进行平均并返回它。但它不是将中间值放入变量中,而是在堆栈上进行所有计算。我可以这样重写它,因为我所有的局部变量和字段都是最终的。
现在有一个问题:如果我正在做一些与字节码生成相关的魔术,并且到处都遵循这种“堆栈上的所有计算”方法(假设我所有的变量和字段都是最终的),我可能会面临哪些潜在的陷阱?
注意:我无意按照我描述的方式重写现有 Java 类的字节码。这里给出的示例类只是为了展示我想在我的字节码中实现的方法语义。