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.
requireNonNull. Checks that the specified object reference is not null and throws a customized NullPointerException if it is. Unlike the method requireNonNull(Object, String) , this method allows creation of the message to be deferred until after the null check is made.
The nonNull method is a static method of the Objects class in Java that checks whether the input object reference supplied to it is non-null or not. If the passed object is non-null, then the method returns true. If the passed object is null , then the method returns false.
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, the iconst_5 instruction in your case.
But the behavior of throwing a NullPointerException when dereferencing null, which would be implied when using a getfield instruction, must be retained¹. So when you change the method to
int sumA() { Temp t = this; return 1 + t.field; } Eclipse will insert an explicit null check too.
So what we see here, is javac failing to recognize that in this specific case, when the reference is this, 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:
If the field is not
static:
- The Primary expression is evaluated. If evaluation of the Primary expression completes abruptly, the field access expression completes abruptly for the same reason.
- If the value of the Primary is
null, then aNullPointerExceptionis thrown.- If the field is a non-blank
final, then the result is the value of the named member field in typeTfound in the object referenced by the value of the Primary.…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With