Java 自動拆箱和自動裝箱學習筆記

Java 自動拆箱和自動裝箱學習筆記

詳情參考如下

1. 概述

Java 中的自動裝箱和自動拆箱算是一種語法糖,也就是在編譯階段編譯器在合適的狀況下幫咱們的作了自動拆箱和自動裝箱。html

衆所周知,Java 中的基本數據類型並非對象,爲了解決在必定切狀況下咱們須要使用對象的時候,Java 爲咱們提供了每一個基本類型對應的包裝類,以下表:java

基本數據類型 數據類型包裝類
byte(1字節) Byte
short(2個字節) Short
int(4個字節) Integer
long(8個字節) Long
float(4個字節) Float
double(8個字節) Double
boolean Boolean
  • 當基本數據類型轉換成數據類型包裝類時,稱之爲裝箱
  • 當數據類型包裝類轉換成基本數據類型時,稱之爲拆箱
Integer i = 10; // 裝箱
    int num = i; // 拆箱

2. 自動拆箱和自動裝箱的實現原理。

對於上面一段代碼進行反編譯能夠獲得:編程

0: bipush        10
    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

能夠看出:裝箱是Integer.valueOf() 方法,而拆箱是調用Integer.intValue() 方法,其餘類型亦是如此。裝箱時調用包裝類的valueOf()方法,拆箱是調用包裝類xxValue()方法。緩存

3. 自動拆箱和自動裝箱的發生時機

在下面的兩種狀況時,會發生自動裝箱oracle

  • 基本類型做爲參數傳遞到相應的包裝類型方法
  • 基本類型分配到相應的包裝類型變量

對應以下代碼:性能

// 基本類型做爲參數傳遞到相應的包裝類型方法
    List<Integer> li = new ArrayList<>();
        for (int i = 1; i < 50; i += 2)
            li.add(i);

    // 基本類型分配到相應的包裝類型變量
    Integer i = 10;

在下面的兩種狀況時,會發生自動拆箱學習

  • 包裝類型做爲參數傳遞給基本類型的方法
  • 包裝類型分配到基本類型的變量

同時在進行 +,- 時,也會發生自動拆箱,由於 Integer 或其餘包裝類型對象沒法使用運算符。因此編譯時,若是包裝類型使用運算符進行運算,會先進行自動拆箱再進行運算。.net

還有一種狀況,就是在使用三目運算符的狀況下,可能會發生自動拆箱。當返回的兩個參數並非同一種數據類型時,編譯器會進行自動拆箱,向下轉型。只要一個運算中有不一樣的類型,涉及到類型轉換,那麼編譯器會往下(基本類型)轉型,再進行運算,以下:指針

 
Double db1 = null;
    Long l2 = null;
    boolean flag =false;
    Double db2 = (flag) ? db1 : l2;
其中 db1 l2 不是同一種類型的參數,編譯器會進行自動拆箱。

對應以下代碼:code

// 包裝類型做爲參數傳遞給基本類型的方法
    Integer i = new Integer(10);
    int i2 = getIntVal(i);
    private static int getIntVal(int i){
        return i;
    }

    // 基本類型分配到相應的包裝類型變量
    int i  = new Integer(10);

4. 關於包裝類 valueOf() 方法

首先看下面一段代碼:

Integer i1 = 10;
    Integer i2 = 10;
    Integer i3 = 200;
    Integer i4 = 200;
    System.out.println(i1 == i2); // true
    System.out.println(i3 == i4); // false

爲何會產生上面的狀況,前面提到,自動裝箱調用的時valueOf() 方法,因此先看一下valueOf() 的源碼:

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

這段代碼的意思時,每次調用Integer.valueOf() 方法時,若是在-128-127之間就會直接從緩存中取。這樣作的緣由是,咱們在使用Integer 時大部分使用的數字都較小,這樣能夠提升效率,節省空間。

不單單是Integer,其餘包裝類有緩存:

  • Boolean 緩存了 Booelan.TRUE 和 Booelan.FALSE
  • Short 緩存了 -128 - 127 之間的值
  • Long 緩存了 -128 - 127 之間的值
  • Byte 數值有限,因此所有都被緩存。
  • Character 緩存了'\u0000' 到 '\u007F'

只有double和float的自動裝箱代碼沒有使用緩存,而double、float是浮點型的,沒有特別的熱的(常常使用到的)數據的,緩存效果沒有其它幾種類型使用效率高

5. 自動拆箱和自動裝箱的優缺點

  • 自動拆箱和自動裝箱的引入方便了咱們編寫程序,提升編程效率

雖然自動拆箱和自動裝箱很方便,可是咱們在使用是須要注意自動拆裝箱所帶來的問題:

  • 因爲包裝類型是對象,就可能在咱們不經意的狀況下產生了空指針異常。若是對一個空的包裝類型對象進行拆箱操做,就會拋出空指針異常。
  • 自動拆裝箱會較爲消耗性能,在性能敏感且操做數量大的狀況下,性能會明顯降低。

因此要建議避免無心中的裝箱、拆箱行爲

相關文章
相關標籤/搜索