成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java自動(dòng)拆箱空指針異常,救火隊(duì)員上線

開(kāi)發(fā) 后端
公司搬遷,臨時(shí)充當(dāng)裝修工,提前兩個(gè)小時(shí)到公司忙著拆卸設(shè)備。結(jié)果接到客戶反映,某部分功能偶爾不能用。于是參與救火,與寫(xiě)這段代碼的小伙伴一起排查原因。

[[384076]]

本文轉(zhuǎn)載自微信公眾號(hào)「程序新視界」,作者二師兄 。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序新視界公眾號(hào)。 

公司搬遷,臨時(shí)充當(dāng)裝修工,提前兩個(gè)小時(shí)到公司忙著拆卸設(shè)備。結(jié)果接到客戶反映,某部分功能偶爾不能用。于是參與救火,與寫(xiě)這段代碼的小伙伴一起排查原因。

最終發(fā)現(xiàn)導(dǎo)致業(yè)務(wù)偶爾不能使用是由Long類(lèi)型自動(dòng)拆箱導(dǎo)致空指針異常引起的。下面就帶大家分析一下Java中基礎(chǔ)類(lèi)型的包裝類(lèi)在拆箱和裝箱過(guò)程中都做了什么,為什么會(huì)出現(xiàn)空指針異常,以及面試過(guò)程中會(huì)出現(xiàn)的相關(guān)面試題。

問(wèn)題重現(xiàn)

下面通過(guò)一個(gè)簡(jiǎn)單的示例才重現(xiàn)一下異常出現(xiàn)的場(chǎng)景。

  1. public class BoxTest { 
  2.  
  3.     public static void main(String[] args) { 
  4.         Map<String,Object> result = httpRequest(); 
  5.         long userId = (Long) result.get("userId"); 
  6.     } 
  7.  
  8.     // 模擬一個(gè)HTTP請(qǐng)求 
  9.     private static Map<String,Object> httpRequest(){ 
  10.         Map<String,Object> map = new HashMap<>(); 
  11.         map.put("userId",null); 
  12.         return map; 
  13.     } 

基本的場(chǎng)景就是請(qǐng)求一個(gè)接口,去接口中取某個(gè)值,這個(gè)值為L(zhǎng)ong類(lèi)型,從Map中取得值之后,進(jìn)行Long類(lèi)型的強(qiáng)轉(zhuǎn)。當(dāng)接口返回的userId為null時(shí),強(qiáng)轉(zhuǎn)這塊就拋出空指針異常:

  1. Exception in thread "main" java.lang.NullPointerException 
  2.  at com.choupangxia.box.BoxTest.main(BoxTest.java:15) 

上面的場(chǎng)景跟下面的代碼出現(xiàn)異常效果一樣:

  1. public class BoxTest { 
  2.  
  3.     public static long getValue(long value) { 
  4.         return value; 
  5.     } 
  6.  
  7.     public static void main(String[] args) { 
  8.         Long value = null
  9.         getValue(value); 
  10.     } 

上述代碼也是將Long類(lèi)型進(jìn)拆箱導(dǎo)致的異常,只不過(guò)一個(gè)在代碼中,一個(gè)在參數(shù)中。為了分析更簡(jiǎn)化,我們以第二個(gè)為例進(jìn)行講解。

原因分析

最初大家可能會(huì)疑惑,拋出異常的代碼都沒(méi)有對(duì)象的方法調(diào)用,怎么會(huì)出現(xiàn)空指針呢?

這中間主要涉及到的就是一個(gè)自動(dòng)拆箱操作。是否是拆箱導(dǎo)致的呢?我們來(lái)通過(guò)字節(jié)碼看一下。

通過(guò)javap -c來(lái)查看一下對(duì)應(yīng)的字節(jié)碼:

  1. public class com.choupangxia.box.BoxTest { 
  2.   public com.choupangxia.box.BoxTest(); 
  3.     Code: 
  4.        0: aload_0 
  5.        1: invokespecial #1                  // Method java/lang/Object."<init>":()V 
  6.        4: return 
  7.  
  8.   public static long getValue(long); 
  9.     Code: 
  10.        0: lload_0 
  11.        1: lreturn 
  12.  
  13.   public static void main(java.lang.String[]); 
  14.     Code: 
  15.        0: aconst_null 
  16.        1: astore_1 
  17.        2: aload_1 
  18.        3: invokevirtual #2                  // Method java/lang/Long.longValue:()J 
  19.        6: invokestatic  #3                  // Method getValue:(J)J 
  20.        9: pop2 
  21.       10: return 

其中g(shù)etValue方法調(diào)用對(duì)應(yīng)的是main方法中編號(hào)3和6的操作。編號(hào)3為命令invokevirtual為方法指令。對(duì)應(yīng)的便是value.longValue,value對(duì)應(yīng)的就是聲明的Long類(lèi)型。

也就是說(shuō)編譯器將getValue(value)拆分成了兩步,第一步將通過(guò)value的longValue方法將其拆箱,然后再將拆箱之后的結(jié)果傳遞給方法。相當(dāng)于:

  1. long primitive = value.longValue(); 
  2. test(promitive); 

對(duì)照最開(kāi)始的代碼,如果value為null的話,那么在調(diào)用longValue方法時(shí)便會(huì)拋出NullPointerException。

所以,本質(zhì)上來(lái)講,所謂的自動(dòng)拆箱和裝箱只不過(guò)是Java提供的語(yǔ)法糖而已。

再次證實(shí)

下面用int類(lèi)型的實(shí)例同時(shí)證實(shí)一下自動(dòng)拆箱和自動(dòng)裝箱兩個(gè)操作語(yǔ)法糖底層到底是怎么運(yùn)行的:

  1. public class IntBoxTest { 
  2.  
  3.     public static void main(String[] args) { 
  4.         Integer index = 11; 
  5.         int primitive = index
  6.     } 

同樣查看上面代碼的字節(jié)碼:

  1. public class com.choupangxia.box.IntBoxTest { 
  2.   public com.choupangxia.box.IntBoxTest(); 
  3.     Code: 
  4.        0: aload_0 
  5.        1: invokespecial #1                  // Method java/lang/Object."<init>":()V 
  6.        4: return 
  7.  
  8.   public static void main(java.lang.String[]); 
  9.     Code: 
  10.        0: bipush        11 
  11.        2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer
  12.        5: astore_1 
  13.        6: aload_1 
  14.        7: invokevirtual #3                  // Method java/lang/Integer.intValue:()I 
  15.       10: istore_2 
  16.       11: return 

可以看到main方法部分,編號(hào)2進(jìn)行了裝箱操作,將原始類(lèi)型int,裝箱成了Integer,調(diào)用的方法為Integer.valueOf;而編號(hào)7進(jìn)行了拆箱操作將Integer類(lèi)型轉(zhuǎn)換成了int類(lèi)型,調(diào)用的方法為Integer.intValue。

自動(dòng)拆箱裝箱的本質(zhì)

通過(guò)上面的分析,我們可以看出所謂的拆箱(unboxing)和裝箱(boxing)操作只不過(guò)是一個(gè)語(yǔ)法糖的功能。編譯器在編譯操作時(shí),本質(zhì)上還是會(huì)調(diào)用對(duì)應(yīng)包裝類(lèi)的不同方法來(lái)進(jìn)行處理。

裝箱時(shí)通常會(huì)調(diào)用包裝類(lèi)的valueOf方法,而拆箱時(shí)通常會(huì)調(diào)用包裝類(lèi)的xxxValue()方法,其中xxx為類(lèi)似boolean/long/int等。

而自動(dòng)拆箱和裝箱的操作主要發(fā)生在賦值、比較、算數(shù)運(yùn)算、方法調(diào)用等常見(jiàn)。此時(shí),我們就需要主要空指針的問(wèn)題。

面試題

看一個(gè)面試題:請(qǐng)問(wèn)下面foo1和foo2被調(diào)用時(shí)如何執(zhí)行?并簡(jiǎn)單分析一下。

  1. public void foo1() { 
  2.     if ((Integernull == 1) { 
  3.     } 
  4.  
  5. public void foo2() { 
  6.     if ((Integernull > 1) { 
  7.         System.out.println("abc"); 
  8.     } 

很明顯在調(diào)用兩個(gè)方法時(shí)都會(huì)拋出空指針異常。關(guān)于拋空指針異常的原因及分析過(guò)程,上文已經(jīng)講過(guò),大家可以嘗試分析一下字節(jié)碼。

再看一個(gè)面試題:下面的語(yǔ)句能正常執(zhí)行嗎?

  1. Integer value1 = (Integernull
  2. Double value2 = (Doublenull
  3. Boolean value3 = (Boolean) null

答案:可以正常執(zhí)行。在Java中null是一個(gè)特殊的值,可以賦值給任何引用類(lèi)型,也可以轉(zhuǎn)化為任何引用類(lèi)型。

小結(jié)

任何一個(gè)小的問(wèn)題,小的異常,如果深入追蹤一下,不僅能夠更清楚的明白底層原理,而且還可以在實(shí)踐的過(guò)程中更有把握,更少犯錯(cuò)。

責(zé)任編輯:武曉燕 來(lái)源: 程序新視界
相關(guān)推薦

2010-08-11 17:11:15

2018-02-08 09:34:34

2021-08-02 09:02:27

架構(gòu)產(chǎn)品優(yōu)化

2020-01-06 08:40:11

阿里場(chǎng)景服務(wù)

2012-03-26 11:32:45

Java

2025-04-03 08:20:00

運(yùn)維系統(tǒng)架構(gòu)

2015-09-02 10:12:54

Java自動(dòng)裝箱拆箱

2015-07-30 10:12:32

JavaNullAssert

2022-01-19 09:00:00

Java空指針開(kāi)發(fā)

2023-10-08 11:09:22

Optional空指針

2012-09-24 10:14:46

Linux系統(tǒng)管理

2011-01-10 14:24:35

CIO快樂(lè)運(yùn)維

2009-08-26 03:39:00

C#裝箱和拆箱

2021-05-12 07:03:25

Switch報(bào)空指針

2015-12-31 13:56:09

創(chuàng)業(yè)

2020-11-02 13:06:42

Java裝箱拆箱

2009-05-26 15:29:28

網(wǎng)管系統(tǒng)設(shè)備維護(hù)摩卡軟件

2015-03-30 16:07:35

福祿克網(wǎng)絡(luò)/網(wǎng)絡(luò)測(cè)試

2024-02-01 12:09:17

Optional容器null

2024-02-28 09:03:20

Optional空指針Java
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产色网站 | 中文在线一区二区 | 女人牲交视频一级毛片 | 欧美成人免费在线 | 成人在线视频观看 | 久久久久久免费看 | 国产一区电影 | 黄网免费 | 国产综合久久 | 成年无码av片在线 | 看av在线 | 国产丝袜一区二区三区免费视频 | 亚洲视频在线一区 | 日韩免费在线 | 九九亚洲 | 亚洲精品免费视频 | 亚洲热在线视频 | 国产丝袜一区二区三区免费视频 | 日本aa毛片a级毛片免费观看 | 免费在线观看av片 | 国产精品区二区三区日本 | 国产午夜亚洲精品不卡 | 亚洲成人av在线播放 | 中文字幕一区二区三区四区五区 | 国产精品一区二区久久 | 天天操一操 | 成人免费看黄网站在线观看 | 一本一道久久a久久精品综合 | 嫩草网| 国产福利网站 | 狠狠操婷婷 | 精品av久久久久电影 | 日韩成人在线观看 | 一区二区三区小视频 | 亚洲精品视频免费观看 | 99pao成人国产永久免费视频 | 国产一区二区三区四区三区四 | 天天看天天爽 | 成人一级毛片 | 天天干干| 男女网站在线观看 |