Consider the following class:
class Temp {
private final int field = 5;
int sum() {
return 1 + this.field;
}
}
Then I compile and decompile the class:
> 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
In simple words, javac compiles sum() to this:
int sum() {
final int n = 1;
Objects.requireNonNull(this); // <---
return n + 5;
}
What is Objects.requireNonNull(this) doing here? What's the point? Is this somehow connected to reachability?
The Java 8 compiler is similar. It inserts this.getClass() instead of Objects.requireNonNull(this):
int sum() {
final int n = 1;
this.getClass(); // <---
return n + 5;
}
I also tried to compile it with Eclipse. It doesn't insert requireNonNull:
int sum() {
return 1 + 5;
}
So this is javac-specific behavior.
Since the field is not only
final, but a compile-time constant, it will not get accessed when being read, but the read gets replaced by the constant value itself, theiconst_5instruction in your case.But the behavior of throwing a
NullPointerExceptionwhen dereferencingnull, which would be implied when using agetfieldinstruction, must be retained¹. So when you change the method toEclipse will insert an explicit null check too.
So what we see here, is
javacfailing to recognize that in this specific case, when the reference isthis, the non-null property is guaranteed by the JVM and hence, the explicit null check is not necessary.¹ see JLS §15.11.1. Field Access Using a Primary: