雲棲號資訊:【點擊查看更多行業資訊】
在這裏您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!
Java中自動裝箱和拆箱
裝箱(Boxing),也稱爲包裝(Wrapper),是在對象中放置原語類型(primitive type)的過程,以便原語(primitive)可以作爲引用對象使用。
這裏的primitive type就是Java裏面的基本類型,所有的基本類型都有一個與之對應的類。例如,Integer類對應基本類型int。
通常,這些類稱爲包裝器(wrapper)。這些對象包裝器類擁有很明顯的名字:Integer、Long、Float、Double、Short、Byte、Character、Void和Boolean(前6個類派生於公共的超類Number)。
對象包裝器類是不可變的,即一旦構造了包裝器,就不允許更改包裝在其中的值。同時,對象包裝器類還是final,因此不能定義它們的子類。
自動裝箱是指通過類型轉換(隱式或顯式)從值類型中獲取引用類型,這部分工作是編譯器幫我們來完成的。
我們看一個常見的例子,比如我們創建一個int類型的ArrayList(因爲ArrayList的泛型是不允許基本類型的,這裏只能使用它們包裝類),我們給ArrayList添加元素,再從裏面獲取元素,一般是這麼寫的:
// int類型的自動裝箱和拆箱
ArrayList<Integer> integerArrayList = new ArrayList<>();
integerArrayList.add(1);
int i = integerArrayList.get(0);
這裏分別觸發了自動裝箱和自動拆箱,這裏的add操作觸發了一次自動裝箱操作,將int轉化爲Integer;接着從ArrayList裏面獲取元素,由於我們的目標變量類型是基本類型int,但獲取到的元素類型是Integer,所以編譯器在這裏幫我們做了拆箱的操作。
通過字節碼查看自動裝箱和自動拆箱是如何實現的
我們經常說自動裝箱、自動拆箱,到底是如何個自動法,我們來一個眼見爲實,通過查看java代碼生成的字節碼來看下編譯器對我們的代碼做了什麼。
查看字節碼的方式
這裏介紹兩種查看字節碼的方式:
- 第一種,通過javac和javap查看:先通過javac將.java代碼編譯成.class字節碼,然後通過javap分析字節碼。
(base) tinytongtongdeMacBook-Pro% javac TestAutoWrapper.java
(base) tinytongtongdeMacBook-Pro% javap -verbose TestAutoWrapper
這樣你就能看到你的字節碼信息了。
- 第二種,通過IDE插件ASM Bytecode Outline來查看,具體操作方式見插件說明。
查看自動裝箱和拆箱的字節碼
public static void main(String[] args) {
// int類型的自動裝箱和拆箱
ArrayList<Integer> integerArrayList = new ArrayList<>();
integerArrayList.add(1);// 自動裝箱
int i = integerArrayList.get(0);// 自動拆箱
}
我們生成這段java代碼的字節碼,核心部分如下:
// access flags 0x9
public static main([Ljava/lang/String;)V
...
L1
LINENUMBER 15 L1
ALOAD 1
ICONST_1
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
POP
L2
LINENUMBER 16 L2
ALOAD 1
ICONST_0
INVOKEVIRTUAL java/util/ArrayList.get (I)Ljava/lang/Object;
CHECKCAST java/lang/Integer
INVOKEVIRTUAL java/lang/Integer.intValue ()I
ISTORE 2
...
L1部分中的倒數第二行,INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z,INVOKEVIRTUAL指令表示一個虛方法調用,這裏具體就是我們java代碼中的integerArrayList.add(1);,自動裝箱發生在哪呢?就在它上面,INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;,INVOKESTATIC表示靜態方法調用,這裏對應的Java語句就是Integer#valueOf()方法。
接下來我們看下自動裝箱對應的字節碼,也就是L2部分,先看INVOKEVIRTUAL java/util/ArrayList.get (I)Ljava/lang/Object;,它對應的java代碼是integerArrayList.get(0),表示從ArrayList裏面獲取到Integer類型對象。自動拆箱發生在下面,就是NVOKEVIRTUAL java/lang/Integer.intValue ()I這條指令,它對應的java方法是Integer#intValue()方法。
看到這裏相信大家對自動裝箱和拆箱有一個比較具體的認識了,說白了就是編譯器會根據情況替我們做一些工作,通過插入字節碼指令來替我們完成裝箱和拆箱操作。int對應的裝箱方法是Integer#valueOf,拆箱方法是Integer#intValue()。
自動裝箱和拆箱的觸發時機
我們接着講下自動裝箱和拆箱的觸發時機,具體如下:
* 進行 = 賦值操作(裝箱或拆箱)
* 進行+,-,*,/混合運算 (拆箱)
* 進行>,<,==比較運算(拆箱)
* 調用equals進行比較(裝箱)
* ArrayList,HashMap等集合類 添加基礎類型數據時(裝箱)
基本類型自動裝箱和拆箱方法總結
感興趣的同學可以自己試下各種操作下,自動裝箱和拆箱的表現,查看對應的字節碼即可。
【雲棲號在線課堂】每天都有產品技術專家分享!
課程地址:https://yqh.aliyun.com/live立即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK
原文發佈時間:2020-08-04
本文作者:tinyvampirepudge
本文來自:“掘金”,瞭解相關信息可以關注“掘金”