Javap is a built-in JDK tool:

This article uses the following simple Java code as an example.

class Outer {
    Nested nested;
    Nested getNested(a) {
        returnnested; }}class Nested {
    Inner inner;
    Inner getInner(a) {
        returninner; }}class Inner {
    String foo;
    String getFoo(a) {
        returnfoo; }}public class NullableTest {
    public static Outer getInitializedOuter(a){
        Outer outer = new Outer();
        outer.nested = new Nested();
        outer.nested.inner = new Inner();
        outer.nested.inner.foo = "Jerry";
        return outer;
    }
    /* null pointer exception private static void way0(){ Outer outer = new Outer(); System.out.println(outer.nested.inner.foo); } * /
    public static void way1(a){
        Outer outer = getInitializedOuter();
        if(outer ! =null&& outer.nested ! =null&& outer.nested.inner ! =null) { System.out.println(outer.nested.inner.foo); }}public static void main(String[] args) {
        //way0();way1(); }}Copy the code

Decomcompile NullableTest to the bytecode generated by the Java compiler using the following command line:

javap -v NullableTest >c:\code\1.txt

Look at the bytecode of way1() :

The following wiki contains a detailed description of each instruction in Java bytecode:

En.wikipedia.org/wiki/Java_b…

NullableTest decompilated bytecode to NullableTest

0: invokestatic #42 // Method getInitializedOuter:()Ljava8/Outer;

Represents a call to the static method getInitializedOuter, Ljava8/Outer meaning that the method’s return type is Outer

3: astore_0

Store the outer reference returned by the static method call above in a local variable with id 0.

4: aload_0

Because IN my previous Java source CODE, I compared object references returned by static methods to NULL, I used the aload_0 directive to reload the object references stored in a local variable codenamed 0 onto the stack before I could compare them to NULL.

5: ifnull 41

This is the IF branch I wrote in the Java source code. IF the outer reference checked in the IF branch is null, it returns directly. If ifnull is true, it jumps to line 41 bytecode, which returns directly.

If ifnull is not true, execution continues. The OUTER reference is also loaded onto the stack.

One interesting observation from the bytecode analysis is to look again at our IF statement.

When Java compiles, the compiler actually converts it to the following:

if (outer == null )

return;

if( outer.nested == null )

return;

if( outer.nested.inner == null)

return;

System.out.println(outer.nested.inner.foo);
Copy the code

This fact can be confirmed by the following figure.

LineNumberTable in the bytecode generated by Javap is also useful. The number after each line in the table represents the sequence number of the Java source code, and the number after the line XX colon represents the sequence number of each line of instructions in the bytecode. Look at the mapping between the Java source code and the corresponding byte instructions in LineNumberTable below.

LineNumberTable maintains the mapping between Java source code and byte instructions, ensuring smooth debugging of Java code.

For more of Jerry’s original technical articles, please follow the public account “Wang Zixi” or scan the following QR code: