您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關Java項目中出現自動拆箱空指針異常如何解決,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
Java的特點有哪些 1.Java語言作為靜態面向對象編程語言的代表,實現了面向對象理論,允許程序員以優雅的思維方式進行復雜的編程。 2.Java具有簡單性、面向對象、分布式、安全性、平臺獨立與可移植性、動態性等特點。 3.使用Java可以編寫桌面應用程序、Web應用程序、分布式系統和嵌入式系統應用程序等。
問題重現
public class BoxTest { public static void main(String[] args) { Map<String,Object> result = httpRequest(); long userId = (Long) result.get("userId"); } // 模擬一個HTTP請求 private static Map<String,Object> httpRequest(){ Map<String,Object> map = new HashMap<>(); map.put("userId",null); return map; } }
基本的場景就是請求一個接口,去接口中取某個值,這個值為Long類型,從Map中取得值之后,進行Long類型的強轉。當接口返回的userId為null時,強轉這塊就拋出空指針異常:
Exception in thread "main" java.lang.NullPointerException
at com.choupangxia.box.BoxTest.main(BoxTest.java:15)
上面的場景跟下面的代碼出現異常效果一樣:
public class BoxTest { public static long getValue(long value) { return value; } public static void main(String[] args) { Long value = null; getValue(value); } }
上述代碼也是將Long類型進拆箱導致的異常,只不過一個在代碼中,一個在參數中。為了分析更簡化,我們以第二個為例進行講解。
最初大家可能會疑惑,拋出異常的代碼都沒有對象的方法調用,怎么會出現空指針呢?
這中間主要涉及到的就是一個自動拆箱操作。是否是拆箱導致的呢?我們來通過字節碼看一下。
通過javap -c來查看一下對應的字節碼:
public class com.choupangxia.box.BoxTest { public com.choupangxia.box.BoxTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static long getValue(long); Code: 0: lload_0 1: lreturn public static void main(java.lang.String[]); Code: 0: aconst_null 1: astore_1 2: aload_1 3: invokevirtual #2 // Method java/lang/Long.longValue:()J 6: invokestatic #3 // Method getValue:(J)J 9: pop2 10: return }
其中getValue方法調用對應的是main方法中編號3和6的操作。編號3為命令invokevirtual為方法指令。對應的便是value.longValue,value對應的就是聲明的Long類型。
也就是說編譯器將getValue(value)拆分成了兩步,第一步將通過value的longValue方法將其拆箱,然后再將拆箱之后的結果傳遞給方法。相當于:
long primitive = value.longValue(); test(promitive);
對照最開始的代碼,如果value為null的話,那么在調用longValue方法時便會拋出NullPointerException。
所以,本質上來講,所謂的自動拆箱和裝箱只不過是Java提供的語法糖而已。
下面用int類型的實例同時證實一下自動拆箱和自動裝箱兩個操作語法糖底層到底是怎么運行的:
public class IntBoxTest { public static void main(String[] args) { Integer index = 11; int primitive = index; } }
同樣查看上面代碼的字節碼:
public class com.choupangxia.box.IntBoxTest { public com.choupangxia.box.IntBoxTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: bipush 11 2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 5: astore_1 6: aload_1 7: invokevirtual #3 // Method java/lang/Integer.intValue:()I 10: istore_2 11: return }
可以看到main方法部分,編號2進行了裝箱操作,將原始類型int,裝箱成了Integer,調用的方法為Integer.valueOf;而編號7進行了拆箱操作將Integer類型轉換成了int類型,調用的方法為Integer.intValue。
通過上面的分析,我們可以看出所謂的拆箱(unboxing)和裝箱(boxing)操作只不過是一個語法糖的功能。編譯器在編譯操作時,本質上還是會調用對應包裝類的不同方法來進行處理。
裝箱時通常會調用包裝類的valueOf方法,而拆箱時通常會調用包裝類的xxxValue()方法,其中xxx為類似boolean/long/int等。
而自動拆箱和裝箱的操作主要發生在賦值、比較、算數運算、方法調用等常見。此時,我們就需要主要空指針的問題。
看一個面試題:請問下面foo1和foo2被調用時如何執行?并簡單分析一下。
public void foo1() { if ((Integer) null == 1) { } } public void foo2() { if ((Integer) null > 1) { System.out.println("abc"); } }
很明顯在調用兩個方法時都會拋出空指針異常。關于拋空指針異常的原因及分析過程,上文已經講過,大家可以嘗試分析一下字節碼。
再看一個面試題:下面的語句能正常執行嗎?
Integer value1 = (Integer) null; Double value2 = (Double) null; Boolean value3 = (Boolean) null;
答案:可以正常執行。在Java中null是一個特殊的值,可以賦值給任何引用類型,也可以轉化為任何引用類型。
以上就是Java項目中出現自動拆箱空指針異常如何解決,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。