java中的自動拆裝箱詳解


本文首先介紹java中的基本數據類型,后面詳細介紹了自動拆裝箱原理,如有問題,歡迎探討交流。

數據類型

分類

基本數據類型分為三類:

  1. 數值型:數值型又分為整數型和浮點型;
  2. 字符型(char)
  3. 布爾型(boolean)

為什么會有基本數據類型?

因為,在java中new一個對象是存儲在堆里的,對於我們經常操作的數據類型,每次創建對象這樣太消耗資源,因此java提供了8個基本數據類型,存儲在棧里。用起來更方便。

8種基本數據類型

為了先理解它們的表數范圍,我們先來介紹一下一些基本知識。

計算機中都是使用二進制的補碼進行運算的,首先,我們知道1字節=8bit,那么8bit可以表示的數字范圍是[-128,127]。注意首位的1表示負數,0表示正數。

1000 0000:-128或-2^7-1

0111 1111:127或2^7-1

類型 占用存儲空間 表數范圍 默認值
byte 1字節 -128 ~ 127 0
short 2字節 -2^15 ~ 2^15 -1 0
int 4字節 -2^31 ~ 2^31 -1 0
long 8字節 -2^63 ~ 2^63 -1 0,或者0L或者0l
float 4字節 -3.403E38 ~ 3.403E38 0.0F或0.0f
double 8字節 -1.798E308 ~ 1.798E308 0.0D或0.0d
char 2字節 0~2^16 -1 '\u0000'
boolean 1字節 true/false false

自動類型轉換

轉換前的數據類型的位數低於轉換后的數據類型。

例如: short數據類型的位數為16位,就可以自動轉換位數為32的int類型,同樣float數據類型的位數為32,可以自動轉換為64位的double類型。

低  ------------------------------------>  高

byte,short,char—> int —> long—> float —> double 

數據類型轉換必須滿足如下規則:

  • 不能對boolean類型進行類型轉換。

  • 不能把對象類型轉換成不相關類的對象。

  • 由大到小會丟失精度:在把容量大的類型轉換為容量小的類型時必須使用強制類型轉換。

    強制類型轉換

    • 條件是轉換的數據類型必須是兼容的。
    • 格式:(type)value type是要強制類型轉換后的數據類型
  • 轉換過程中可能導致溢出或損失精度,例如:

    int i =128;   
    byte b = (byte)i;//-128
    

    因為 byte 類型是 8 位,最大值為127,所以當 int 強制轉換為 byte 類型時,值 128 時候就會導致溢出。

  • 浮點數到整數的轉換是通過舍棄小數得到,而不是四舍五入,例如:

    (int)23.7 == 23;        
    (int)-45.89f == -45
    

包裝類

出現原因

簡單來說,就是讓基本數據類型的變量具有類中對象的特征。

基本數據類型,使用起來非常方便,但是沒有對應的方法來操作這些基本類型的數據,可以使用一個類,把基本數據類型的數據裝起來,這個類叫做包裝類(wrapper)。這樣我們可以調用類中的方法。

開發中,用的最多的是字符串變為基本數據類型。

8種基本數據類型對應包裝類:可以看到除了int和char類型,其它都是首字母大寫。

基本數據類型 包裝類
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

裝箱

即對基本類型進行包裝,基本類型->包裝類

  • 通過包裝類的構造器實現(jdk1.5之前)

    Integer t = new Integer(10);
    
  • 通過字符串參數構造包裝類對象

    Float f = new Float("4.56");
    Long l = new Long("wer");//NumberFormatException
    
  • 自動裝箱(jdk1.5之后)

    Integer i = 100;替代了 Integer i = new Integer(100);,因為Java幫我們提供了自動裝箱的功能,不需要開發者手動去new一個Integer對象。

    Integer i = 100;//自動裝箱
    //相當於編譯器自動作以下的語法編譯:Integer i = Integer.valueOf(100);
    

拆箱

包裝類->基本類型

  • 調用包裝類中的.xxxValue()方法

    Integer t = 128; // 此時t就是一個包裝類
    System.out.println(t.intValue());//128
    
  • 自動拆箱

    Integer i = 10; //自動裝箱 
    int t = i; //自動拆箱,實際上執行了 int t = i.intValue();
    

自動裝箱和自動拆箱的實現原理

Integer integer = 1;
//自動裝箱,相當於Integer integer = Integer.valueOf(1);
int i = integer;
//自動拆箱,相當於int i = integer.intValue();

對於上面的代碼,Java是怎么做的呢?

自動裝箱:調用valueOf()方法將原始類型值轉換成對象

自動拆箱:調用intValue()方法,其他的(xxxValue())這類的方法將對象轉換成原始類型值。

類型間轉換

基本數據類型->String類

  • String類的valueOf()方法:String fs = String.valueOf(2.34f);
  • 更直接的方式5+""

String類->基本數據類型

  • 通過包裝類的構造器實現:int i = new Integer("12")
  • 通過調用包裝類的parseXxx(字符串)該靜態方法:Float f = Float.parseFloat("12.1");

包裝類->String類

  • 包裝類對象的toString()方法

    Integer t = new Integer(100);
    String s = t.toString();// s = "100";
    //將數字轉換為字符串
    
  • 調用包裝類的toString(形參)方法

    String s1 = Integer.toString(314); // s1= "314" 將數字轉換成字符串。
    

String類->包裝類

  • 通過字符串參數

    Float f = new Float("3.14f");
    

自動拆裝箱與緩存

總結

  • int 是基本數據類型
  • Integer是包裝類,Integer i = num,自動裝箱而num值的范圍如果取(-128<=num<=127),那么就在IntegerCache中直接取已經創建好的對象,不會創建新的Integer對象
  • new Integer() 在堆中創建新的Integer對象
  • 無論是Integer i1 = num還是Integer i2 = new Integer(num);,i1與i2之間的比較==牽扯到對象的比較,對於對象比較,==比較的是地址。

具體請看下面的例子:

Integer和int比較

int 和 Integer在進行比較的時候,Integer會進行拆箱,轉為int值與int進行比較

@Test
public void testInteger(){
    Integer i = 10;
    int i1 = 10;
    System.out.println(i == i1); //true

    Integer i2 = 300;
    int i3 = 300;
    System.out.println(i2 == i3); //true
}

Integer與Integer比較

Integer與Integer比較的時候,由於直接賦值的時候會進行自動裝箱。那么這里就需要注意兩個問題

  1. -128<= x<=127的整數,將會直接緩存在IntegerCache中,那么當賦值在這個區間的時候,不會創建新的Integer對象,而是從緩存中獲取已經創建好的Integer對象。
  2. 大於這個范圍的時候,直接new Integer來創建Integer對象。
@Test
public void testInteger2(){
    System.out.println("Integer與Integer比較");

    Integer i6 = 128;
    Integer i7 = 128;
    System.out.println(i6 == i7);//false
    // i6自動裝箱產生的Integer對象,大小超過了-128——127的范圍,這里會直接創建該對象:new Integer(128)
    // i7同理。它們在堆中的地址是不同的,因此false.

    Integer i4 = 1;
    Integer i5 = 1;
    System.out.println(i4 == i5); //true
    // i4、i5都是從IntegerCache中取出來的對象,故true;

    Integer i8 = 127;
    Integer i9 = 127;
    System.out.println(i8 == i9);//true
    // i8、i9都是從IntegerCache中取出來的對象,故true;

    Integer i10 = new Integer(127);
    Integer i11 = 127;
    System.out.println(i10 == i11); //false
    // i10是創建的一個Integer的對象,取值是127
    // i11是進行自動裝箱后生成的Integer對象,在-128——127之間,是直接從緩存IntegerCache中取出來的對象
    // i10是自己new出來的對象,i11是從IntegerCache中取的對象,地址不同,故false.

    Integer i12 = new Integer(128);
    Integer i13 = 128;
    System.out.println(i12 == i13);//false
    // 說明:i12是創建的一個Integer的對象,取值是128
    // i13 是進行自動裝箱的實例,這里超出了-128——127的范圍,創建了新的Integer對象。
    // 二者存儲在堆中,分配的地址不同,因此用==判斷時,由於對象的地址不同,所以false.
}
}

參考鏈接

https://blog.csdn.net/wufaliang003/article/details/82347077#comments

https://blog.csdn.net/wangyang1354/article/details/52623703

https://www.cnblogs.com/wang-yaz/p/8516151.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM