天天看點

JAVA-自動裝箱拆箱的秘密

作者:會程式設計的東北虎

作為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種類型也是如此。

繼續閱讀