本文首先介紹java中的基本數據類型,后面詳細介紹了自動拆裝箱原理,如有問題,歡迎探討交流。
數據類型
分類
基本數據類型分為三類:
- 數值型:數值型又分為整數型和浮點型;
- 字符型(char)
- 布爾型(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比較的時候,由於直接賦值的時候會進行自動裝箱。那么這里就需要注意兩個問題
- -128<= x<=127的整數,將會直接緩存在IntegerCache中,那么當賦值在這個區間的時候,不會創建新的Integer對象,而是從緩存中獲取已經創建好的Integer對象。
- 大於這個范圍的時候,直接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