java 字节码分析_使用javap分析Java字节码的一个例子

I have the following source code in 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 exceptionprivate 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();

}}

Get de-assembled byte code via javap:

200336815_1_2020082603581683.png

Navigate to the part for method way1():

200336815_2_20200826035816146_wm.jpg

According to instruction list explanation in wiki:

0: invokestatic #42 // Method getInitializedOuter:()Ljava8/Outer; Call static method getInitializedOuter, whose return type is Outer 3: astore_0 Store returned Outer reference to local variable with id 0 4: aload_0 Since in Java source code, the reference outer will be compared against null via outer != null, so here aload_0 loads the reference stored in local variable #0 to stack. 5: ifnull 41 If the current value is null, execution will go to code #41, which is directly return.

200336815_3_20200826035816318_wm.jpg

or else continue to execute from #8: aload_0 to fetch outer into stack again. Why repeated call a_load_0 for loading outer reference is needed here? Again check the instruction list table:

200336815_4_20200826035816396.png

For instruction ifnull, the value in the stack before executed is value, value is gone after ifnull is executed.

200336815_5_20200826035816474.png

From the list above, we can also see another instruction ifnonnull. So here the interesting fact is, according to the analysis so far, the source code below:

if (outer != null && outer.nested != null && outer.nested.inner != null) {

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

is actually compiled by Java as the execution approach below:

if (outer == null )

return;if( outer.nested == null )

return;if( outer.nested.inner == null)

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

200336815_6_20200826035816536_wm.jpg

The usage of LineNumber Table:

200336815_7_20200826035816974_wm.jpg

LineNumberTable is one of the optional attributes that holds metadata for debugging purposes. In this case, it specifies which offsets in the bytecode correspond to each line in the original source code. This is useful for printing more informative stack traces and for providing features like single step in the debugger. The example above illustrates the mapping relationship from byte code and original source code.

When change way1 from public to private, in javap output you cannot find byte code for way1() itself any more.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值