考虑以下类。
class Temp {
private final int field = 5;
int sum() {
return 1 + this.field;
}
}
然后我编译和反编译这个类。
> 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
简单地说, javac
编译 sum()
到这。
int sum() {
final int n = 1;
Objects.requireNonNull(this); // <---
return n + 5;
}
什么是 Objects.requireNonNull(this)
在这里做什么?有什么意义?这和可到达性有什么联系吗?
Java 8编译器也是如此。它插入了 this.getClass()
而不是 Objects.requireNonNull(this)
:
int sum() {
final int n = 1;
this.getClass(); // <---
return n + 5;
}
我也试着用Eclipse编译它。它没有插入 requireNonNull
:
int sum() {
return 1 + 5;
}
所以这是javac特有的行为。
由于该字段不仅是 final
但是,a 编译时常数当被读取时,它不会被访问,但读取会被常量值本身取代,即 iconst_5
在你的情况下,指令。
但在你的案例中,抛出一个 NullPointerException
当解除引用 null
,这在使用 getfield
指令,必须保留¹。所以当你把方法改为
int sumA() {
Temp t = this;
return 1 + t.field;
}
Eclipse也会插入一个显式的null检查。
所以我们在这里看到的是 javac
没有认识到,在这一具体案例中,当提到的是 this
JVM保证了非空属性,因此,显式空检查是不必要的。
如果该字段不在
static
:
- 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 负责人: 小学 表达式被评估。如果评估了 小学 表达式突然完成,字段访问表达式也会因为同样的原因突然完成。
- 如果字段访问表达式中的 小学 是
null
那么,aNullPointerException
被抛出。- 如果该字段为非空的
final
的成员字段的值,那么结果就是类型为T
的值所引用的对象中找到的。小学.…