最近修改線上bug的時候排查了一個十分隱藏的bug,直接上代碼:
1
2
3
|
integer a = null ; boolean flag = true ; integer b = flag ? a : 0 ; |
乍一看是沒什么毛病的,但是已運行就會發現報空指針,在idea里面也會警告可能有空指針,這是什么原因呢?
直接看字節碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
0 : aconst_null 1 : astore_1 2 : iconst_1 3 : istore_2 4 : iload_2 5 : ifeq 15 8 : aload_1 9 : invokevirtual # 2 // method java/lang/integer.intvalue:()i 12 : goto 16 15 : iconst_0 16 : invokestatic # 3 // method java/lang/integer.valueof:(i)ljava/lang/integer; 19 : astore_3 20 : getstatic # 4 // field java/lang/system.out:ljava/io/printstream; 23 : aload_3 24 : invokevirtual # 5 // method java/io/printstream.println:(ljava/lang/object;)v 27 : return |
可以看到字節碼中調用了`integer.valueof()`
方法,因為我們代碼中一個值使用的是0(基本數據類型int),編譯器就會進行自動拆裝箱(成int),
雖然三目運算的后面邏輯不會執行,但是隱藏的自動拆裝箱會執行`integer.valueof()`方法,也就有了空指針異常。
為了進一步驗證存在自動拆裝箱,把代碼修改一下:
1
2
3
|
integer a = null ; boolean flag = true ; integer b = flag ? a : new integer( 0 ); |
再看字節碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
0 : aconst_null 1 : astore_1 2 : iconst_1 3 : istore_2 4 : iload_2 5 : ifeq 12 8 : aload_1 9 : goto 20 12 : new # 2 // class java/lang/integer 15 : dup 16 : iconst_0 17 : invokespecial # 3 // method java/lang/integer."<init>":(i)v 20 : astore_3 21 : getstatic # 4 // field java/lang/system.out:ljava/io/printstream; 24 : aload_3 25 : invokevirtual # 5 // method java/io/printstream.println:(ljava/lang/object;)v |
可以看到,由于重新創建了一個`integer`對象,并沒有基本類型的存在,也就不存在自動拆裝箱,修改過后的代碼也就不會有問題了,但是idea的警告依舊存在。
這是一個非常隱蔽,也非常容易忽略和踩坑的一個地方,三目運算符的使用應該保證后面的值都是常量,或者統一類型,不然就會出現上面的情況。
更甚三目運算符本身提供的作用也不過是為了簡化邏輯,在其中放入過多的邏輯判斷也就違背了其初衷。
總結
以上所述是小編給大家介紹的java三目運算中隱藏的自動拆裝箱,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的!
原文鏈接:https://minei.me/archives/422.html