作為Java語言使用者,下面是一種很熟悉的操作:
Integer b = 127;
int a = b;
那麼,是不是有過這個疑問:
1、 Java是怎麼把基本資料類型int類型127變為Integer類的執行個體化資料b;
2、 Java是Integer類的執行個體化資料b變為基本資料類型int類型。
在之前的文章講過怎麼認識一個類,class檔案是位元組碼資訊,是JVM的中間碼。那麼我們就通過位元組碼來看看是怎麼裝箱的吧。
一個簡單的類:
package org.test;
public class Test {
Integer b = 100;
int a = b;
}
編譯成class檔案後,通過下面指令
javap -v Test.class
位元組碼資訊如下:
Classfile org/test/Test.class
Last modified 2022-10-21; size 448 bytes
MD5 checksum 33cd1db3d588caccf1b097e1fde54284
Compiled from "Test.java"
public class org.test.Test
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #7.#21 // java/lang/Object."<init>":()V
#2 = Methodref #22.#23 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
#3 = Fieldref #6.#24 // org/test/Test.b:Ljava/lang/Integer;
#4 = Methodref #22.#25 // java/lang/Integer.intValue:()I
#5 = Fieldref #6.#26 // org/test/Test.a:I
#6 = Class #27 // org/test/Test
#7 = Class #28 // java/lang/Object
#8 = Utf8 b
#9 = Utf8 Ljava/lang/Integer;
#10 = Utf8 a
#11 = Utf8 I
#12 = Utf8 <init>
#13 = Utf8 ()V
#14 = Utf8 Code
#15 = Utf8 LineNumberTable
#16 = Utf8 LocalVariableTable
#17 = Utf8 this
#18 = Utf8 Lorg/test/Test;
#19 = Utf8 SourceFile
#20 = Utf8 Test.java
#21 = NameAndType #12:#13 // "<init>":()V
#22 = Class #29 // java/lang/Integer
#23 = NameAndType #30:#31 // valueOf:(I)Ljava/lang/Integer;
#24 = NameAndType #8:#9 // b:Ljava/lang/Integer;
#25 = NameAndType #32:#33 // intValue:()I
#26 = NameAndType #10:#11 // a:I
#27 = Utf8 org/test/Test
#28 = Utf8 java/lang/Object
#29 = Utf8 java/lang/Integer
#30 = Utf8 valueOf
#31 = Utf8 (I)Ljava/lang/Integer;
#32 = Utf8 intValue
#33 = Utf8 ()I
{
java.lang.Integer b;
descriptor: Ljava/lang/Integer;
flags:
int a;
descriptor: I
flags:
public org.test.Test();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 100
7: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
10: putfield #3 // Field b:Ljava/lang/Integer;
13: aload_0
14: aload_0
15: getfield #3 // Field b:Ljava/lang/Integer;
18: invokevirtual #4 // Method java/lang/Integer.intValue:()I
21: putfield #5 // Field a:I
24: return
LineNumberTable:
line 3: 0
line 4: 4
line 5: 13
LocalVariableTable:
Start Length Slot Name Signature
0 25 0 this Lorg/test/Test;
}
SourceFile: "Test.java"
本篇不是關于位元組碼資訊的解讀,不過多說明。
解讀:
第一、關于自動裝箱Integer b = 100,發現b有這行資訊:
10: putfield #3 // Field b:Ljava/lang/Integer;
在這行上面,可以看到一個函數:
7: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
好像代碼中沒有使用Integer.valueOf這個方法。
根據API可知這個函數是把基本資料類型int類型轉為Intenger類型。
這不就是自動裝箱要幹的事嗎!!!
第二、關于自動拆箱int a = b,發現a有這行資訊:
21: putfield #5 // Field a:I
在這行上面,也可以看到一個函數:
18: invokevirtual #4 // Method java/lang/Integer.intValue:()I
好像代碼中沒有使用Integer.intValue這個方法。
根據API可知這個函數是把Intenger類型轉為基本資料類型int類型。
這不就是自動拆箱要幹的事嗎!!!
總結:
自動裝箱拆箱是在JAVA編譯為Class檔案時做了增強處理,減少開發者處理,屏蔽了開發者的感覺。
自動裝箱: 基本類型指派給包裝類型時,使用基本類型對應的包裝類型的valueOf進行包裝。例如: Integer b = 100,在位元組碼中增強實作其實是Integer b = Integer.valueOf(100),同理其他7種類型也是如此。
自動拆箱: 包裝類型指派給基本類型時,使用包裝類型intValue進行 拆包。例如: int a = b,在位元組碼中增強實作其實是int a = Integer.intValue(b),同理其他7種類型也是如此。