Zhe*_*lov 38 java javac java-8 ecj java-11
考虑以下类:
class Temp {
private final int field = 5;
int sum() {
return 1 + this.field;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我编译和反编译这个类:
> javac --version
javac 11.0.5
> javac Temp.java
> javap -v Temp.class
...
int sum();
descriptor: ()I
flags: (0x0000)
Code:
stack=2, locals=1, args_size=1
0: iconst_1
1: aload_0
2: invokestatic #3 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
5: pop
6: iconst_5
7: iadd
8: ireturn
Run Code Online (Sandbox Code Playgroud)
简单来说,javac编译sum()成这样:
int sum() {
final int n = 1;
Objects.requireNonNull(this); // <---
return n + 5;
}
Run Code Online (Sandbox Code Playgroud)
什么是Objects.requireNonNull(this)在这里做什么?重点是什么?这是否与可达性有某种联系?
Java 8 编译器与此类似。它插入this.getClass()而不是Objects.requireNonNull(this):
int sum() {
final int n = 1;
this.getClass(); // <---
return n + 5;
}
Run Code Online (Sandbox Code Playgroud)
我也尝试用 Eclipse 编译它。它不插入requireNonNull:
int sum() {
return 1 + 5;
}
Run Code Online (Sandbox Code Playgroud)
所以这是 javac 特定的行为。
Hol*_*ger 41
由于该字段不仅是final,而且是编译时常量,因此在读取时不会访问它,但读取会被常量值本身替换,即iconst_5您的情况下的指令。
但是,NullPointerException在取消引用时抛出 a 的行为(null在使用getfield指令时隐含)必须保留¹。因此,当您将方法更改为
int sumA() {
Temp t = this;
return 1 + t.field;
}
Run Code Online (Sandbox Code Playgroud)
Eclipse 也会插入一个显式的空检查。
因此,我们在这里看到的是javac未能认识到在这种特定情况下,当引用为 时this,非空属性由 JVM 保证,因此,不需要显式空检查。
¹ 参见JLS §15.11.1。使用主字段访问:
如果该字段不是
static:
- 所述主表达式。如果Primary表达式的计算突然完成,则字段访问表达式也会出于同样的原因突然完成。
- 如果Primary 的值为
null,则NullPointerException抛出 a。- 如果该字段是非空的
final,则结果是在T由Primary的值引用的对象中找到的type 中的命名成员字段的值。…
| 归档时间: |
|
| 查看次数: |
970 次 |
| 最近记录: |