欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java自動(dòng)拆箱空指針異常的解決

 更新時(shí)間:2021年03月04日 10:05:34   作者:secbro2  
這篇文章主要介紹了Java自動(dòng)拆箱空指針異常的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

公司搬遷,臨時(shí)充當(dāng)裝修工,提前兩個(gè)小時(shí)到公司忙著拆卸設(shè)備。結(jié)果接到客戶(hù)反映,某部分功能偶爾不能用。于是參與救火,與寫(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)景。

public class BoxTest {

  public static void main(String[] args) {
    Map<String,Object> result = httpRequest();
    long userId = (Long) result.get("userId");
  }

  // 模擬一個(gè)HTTP請(qǐng)求
  private static Map<String,Object> httpRequest(){
    Map<String,Object> map = new HashMap<>();
    map.put("userId",null);
    return map;
  }
}

基本的場(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)這塊就拋出空指針異常:

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

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

public class BoxTest {

  public static long getValue(long value) {
    return value;
  }

  public static void main(String[] args) {
    Long value = null;
    getValue(value);
  }
}

上述代碼也是將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é)碼:

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
}

其中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)于:

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

對(duì)照最開(kāi)始的代碼,如果value為null的話(huà),那么在調(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)行的:

public class IntBoxTest {

  public static void main(String[] args) {
    Integer index = 11;
    int primitive = index;
  }
}

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

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方法部分,編號(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)單分析一下。

public void foo1() {
  if ((Integer) null == 1) {
  }
}

public void foo2() {
  if ((Integer) null > 1) {
    System.out.println("abc");
  }
}

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

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

Integer value1 = (Integer) null;
Double value2 = (Double) null;
Boolean value3 = (Boolean) null;

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

小結(jié)

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

到此這篇關(guān)于Java自動(dòng)拆箱空指針異常的解決的文章就介紹到這了,更多相關(guān)Java自動(dòng)拆箱空指針異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • Java BigDecimal基礎(chǔ)用法詳解

    Java BigDecimal基礎(chǔ)用法詳解

    Java在java.math包中提供的API類(lèi)BigDecimal,用來(lái)對(duì)超過(guò)16位有效位的數(shù)進(jìn)行精確的運(yùn)算。雙精度浮點(diǎn)型變量double可以處理16位有效數(shù),但在實(shí)際應(yīng)用中,可能需要對(duì)更大或者更小的數(shù)進(jìn)行運(yùn)算和處理
    2022-06-06
  • java中String與StringBuilder的區(qū)別

    java中String與StringBuilder的區(qū)別

    本篇文章介紹了,java中String與StringBuilder的區(qū)別。需要的朋友參考下
    2013-04-04
  • MybatisPlus分頁(yè)失效不起作用的解決

    MybatisPlus分頁(yè)失效不起作用的解決

    在使用MybatisPlus的selectPage時(shí)發(fā)現(xiàn)分頁(yè)不起作用,每次返回的都是全部的數(shù)據(jù),本文就來(lái)介紹一下MybatisPlus分頁(yè)失效不起作用的解決,感興趣的可以了解一下
    2024-03-03
  • spring boot基于Java的容器配置講解

    spring boot基于Java的容器配置講解

    這篇文章主要介紹了spring boot基于Java的容器配置講解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • MyBatis常見(jiàn)報(bào)錯(cuò)問(wèn)題及解決方案

    MyBatis常見(jiàn)報(bào)錯(cuò)問(wèn)題及解決方案

    這篇文章主要介紹了MyBatis常見(jiàn)報(bào)錯(cuò)問(wèn)題及解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Java構(gòu)造函數(shù)里的一些坑記錄super()和this()

    Java構(gòu)造函數(shù)里的一些坑記錄super()和this()

    這篇文章主要介紹了Java構(gòu)造函數(shù)里的一些坑記錄super()和this(),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 一文詳解Reactor模型與實(shí)現(xiàn)示例

    一文詳解Reactor模型與實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了Reactor模型與實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 阿里nacos+springboot+dubbo2.7.3統(tǒng)一處理異常的兩種方式

    阿里nacos+springboot+dubbo2.7.3統(tǒng)一處理異常的兩種方式

    本文主要介紹了阿里nacos+springboot+dubbo2.7.3統(tǒng)一處理異常的兩種方式,文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • SpringBoot執(zhí)行有返回值的異步任務(wù)問(wèn)題

    SpringBoot執(zhí)行有返回值的異步任務(wù)問(wèn)題

    這篇文章主要介紹了SpringBoot執(zhí)行有返回值的異步任務(wù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 基于Java ORM框架的使用詳解

    基于Java ORM框架的使用詳解

    本篇文章是對(duì)Java中ORM框架的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05

最新評(píng)論