且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

一个简单的例子教会您使用javap

更新时间:2022-09-13 11:24:27

一个简单的例子教会您使用javap

这篇文章使用下面这段简单的Java代码作为例子进行讲解。

class Outer {
    Nested nested;
    Nested getNested() {
        return nested;
    }
}
class Nested {
    Inner inner;
    Inner getInner() {
        return inner;
    }
}
class Inner {
    String foo;
    String getFoo() {
        return foo;
    }
}
public class NullableTest {
    public static Outer getInitializedOuter(){
        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(){
        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();
    }
}

一个简单的例子教会您使用javap

下面对NullableTest反编译得到的字节码做一些说明:


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


代表静态方法getInitializedOuter的调用, Ljava8/Outer意思是该方法的返回类型是Outer


3: astore_0


将上述静态方法调用返回的outer引用存储到局部变量中,局部变量的id为0.


4: aload_0


因为在我前面的Java源代码中,我将静态方法返回的对象引用同null做了比较,因此使用指令aload_0将存储在代号为0的局部变量中的对象引用重新加载到栈上,此后才能和null做比较。


5: ifnull 41


这就是我在Java源代码里书写的IF分支。如果IF分支里检测的outer引用为null,则直接返回了。体现在字节码就是,如果ifnull为true,则跳转到第41行字节码,即直接返回。

一个简单的例子教会您使用javap

如果ifnull不为true,则继续执行下去。又将outer引用加载到栈上。

从字节码的分析可以观察到一个有趣的现象,再次看看我们的IF语句。

Java编译时,编译器实际将其转换成了下面的写法:

if (outer == null )

return;

if( outer.nested == null )

return;

if( outer.nested.inner == null)

return;

System.out.println(outer.nested.inner.foo);

一个简单的例子教会您使用javap