Integer轉int出現NullPointException

chadm發表於2020-11-09

之前在專案中,遇到一個Integer轉int出現NullPointException的問題,導致無法開機,記錄一下

示例程式碼如下:

HashMap<String,Integer> typeMap = new HashMap<String,Integer>();
typeMap.put("one",1);
int value = typeMap.get("two");

原因很清楚,當Integer為空的時候,轉換成Int會呼叫Integer.intValue方法,所以出現空指標

1.關於封裝類的一些理解

因為Java語言中,primtive types和Generic(泛型)不能混用,所以引入 autoBoxing和unBoxing,提供了primtive types和class types隱式轉換

  • autoBoxing:將一個基礎型別的值改變成封裝類的過程(如Integer.valueOf())。Java編譯器會在如下2個場景將基礎型別包裝為Object
    • 基礎型別值作為方法的引數,預期的傳入是一個封裝Object
    • 將基礎型別值賦值給封裝類
  • unBoxing:Integer轉Int,Java編譯器會呼叫Integer.intValue,返回一個int值

Integer是int的封裝類,自動封裝和解封裝都是在Java編譯器裡面處理的,其中的過程通過程式碼顯示如下:

Integer integer = 1;
int value = integer;

上面的程式碼通過反編譯javap -c xxx.class檔案

#1 = Methodref          #14.#56        // java/lang/Object."<init>":()V
#2 = Methodref          #44.#57        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
#3 = Methodref          #44.#58        // java/lang/Integer.intValue:()I

2.Java中型別的說明

以下內容摘自JSL CHAPTER 4 Types, Values, and Variables文件

Java是一種靜態語言,在編譯的時候,所有變數和表示式都有自己的型別

Java也是一種強型別語言,因為型別限制了變數和表示式的值,限制可以執行的operations,可以減少編譯時的錯誤

Java語言支援的型別分為2類:primtive types(基礎型別)和refernce types(引用型別).

  • primtive types是指boolean 型別和數字型別,其中數字型別又分為整型(包括byte、short、int、long和char)和浮點型(float、double).換句話我們熟悉的話來說是,8種基礎型別包括boolean、float、double、byte、short、int、long和char
  • refernce types:有3種class types (類), interface types (介面), and array types (陣列).

3.關於Integer的一些理解

Integer的值,注意是final型別的,也就是說建立物件後,這個值不能再發生變化

// Integer的值
private final int value

equals方法是比的value值

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

Integer 類提供了其它型別轉Integer的方法

  • public Integer(String s)
  • public Integer(int value)
  • Integer valueOf(int i)

也提供了Integer轉其它型別的方法

  • byteValue
  • shortValue
  • intValue
  • longValue
  • floatValue
  • doubleValue
  • toString

內部類IntegerCache是實現了JSL 5.1.7 Boxing Conversion裡面的定義,通過快取節約記憶體和提高效能,可以通過 JVM 引數來設定

-XX:AutoBoxCacheMax=size

當建立Integer物件的時候,如果有快取(範圍是 [-128, 127]),則直接取快取的結果,否則建立一個新的Integer物件

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

加深一下理解 ,看如下程式碼的輸出

Integer integer1 = 3;
Integer integer2 = 3;
System.out.println("integer1 == integer2 is " + (integer1 == integer2));
Integer integer3 = 128;
Integer integer4 = 128;
System.out.println("integer3 == integer4 is " + (integer3 == integer4));
Integer integer5 = new Integer(3);
Integer integer6 = new Integer(3);
System.out.println("integer5 == integer6 is " + (integer5 == integer6));

輸出結果是,原因是IntegerCache只快取了-128到127之間的值,所以integer1和integer2是用的同一個快取物件,integer3和integer4是2個不同的物件

integer1 == integer2 is true
integer3 == integer4 is false
integer5 == integer6 is false

注意:
IntegerCache只適用於autoboxing

參考

相關文章