1. 程式人生 > >java基本類型與引用類型

java基本類型與引用類型

float value 賦值 jdk1.5 解釋 eval 查看 因此 常見

目錄
java基本類型與引用類型
目錄
一基本數據類型
二引用類型
三基本類型與引用類型的區別
默認值
內存分配
自動裝箱自動拆箱
自動裝箱拆箱帶來的問題
程序的性能
空指針異常
對象相等比較時
一、基本數據類型
java中一共分為8種基本數據類型:byte、short、int、long、float、double、char、boolean,其中byte、short、int、long是整型。float、double是浮點型,char是字符型,boolean是布爾型。

二、引用類型
java為每種基本類型都提供了對應的封裝類型,分別為:Byte、Short、Integer、Long、Float、Double、Character、Boolean。引用類型是一種對象類型,它的值是指向內存空間的引用,就是地址。

三、基本類型與引用類型的區別
1.默認值
整型byte、short、int、long的默認值都為0,浮點型float、double的默認值為0.0,boolean默認值為false,char默認值為空。對應的包裝類型默認值都為null。

2.內存分配
基本數據類型的變量是存儲在棧內存中,而引用類型變量存儲在棧內存中,保存的是實際對象在堆內存中的地址,實際對象中保存這內容。

3.自動裝箱、自動拆箱
Java從jdk1.5開始引入自動裝箱和拆箱,使得基本數據類型與引用類型之間相互轉換變得簡單。

自動裝箱: java自動將原始類型轉化為引用類型的過程,自動裝箱時編譯器會調用valueOf方法,將原始類型轉化為對象類型。

自動拆箱: java自動將引用類型轉化為原始類型的過程,自動拆箱時編譯器會調用intValue(),doubleValue()這類的方法將對象轉換成原始類型值。

自動裝箱主要發生在兩種情況:一種是賦值時,一種是方法調用時。
a.賦值

Integer a = 3; //自動裝箱
int b = a; //自動拆箱
b.方法調用

public Integer query(Integer a){
return a;
}
query(3); //自動裝箱
int result = query(3); //自動拆箱
4.自動裝箱、拆箱帶來的問題
1.程序的性能
由於裝箱會隱式地創建對象創建,因此千萬不要在一個循環中進行自動裝箱的操作,下面就是一個循環中進行自動裝箱的例子,會額外創建多余的對象,增加GC的壓力,影響程序的性能:

Integer sum = 0;
for(int i=0; i<1000; i++){
sum+=i;
}
2.空指針異常
註意拆箱過程中可能產生的空指針異常,一個簡單的例子:

Object obj = null;
int i = (Integer)obj;
3.對象相等比較時
先來看一個常見的例子:

Integer a = 120;
int b= 120;
Integer c = 120;
Integer d = new Integer(120);
System.out.println(a == b); //true t1
System.out.println(a == c); //true t2
System.out.println(a == d); //false t3

Integer e = 128;
Integer f = 128;
System.out.println(e == f); //false t4
返回結果是不是出乎大家的意料,解釋一下每種結果的原因:
我們先反編譯一下生成字節碼:

Integer a = Integer.valueOf(120);
int b = 120;
Integer c = Integer.valueOf(120);
Integer d = new Integer(120);
System.out.println(a.intValue() == b);
System.out.println(a == c);
System.out.println(a == d);

Integer e = Integer.valueOf(127);
Integer f = Integer.valueOf(127);
System.out.println(e == f);

Integer e1 = Integer.valueOf(128);
Integer f1 = Integer.valueOf(128);
System.out.println(e1 == f1);
可以看到變量a、c在初始化的時候編譯器調用了valueOf進行自動裝箱,在a==b時對變量a調用了intValue()方法進行了自動拆箱操作,這就很好解釋t1~t4的結果了。

t1產生的原因是編譯器編譯時會調用intValue()自動的將a進行了拆箱,結果肯定是true;
t2跟t4的結果比較難理解:這是因為初始化時,編譯器會調用裝箱類的valueOf()方法,查看jdk的源碼:

public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

發現jdk對-128~127之間的值做了緩存,對於-128~127之間的值會取緩存中的引用,通過緩存經常請求的值而顯著提高空間和時間性能。
這就能解釋t2結果返回true,而t4由於128不在緩存區間內,編譯器調用valueOf方法會重新創建新的對象,兩個不同的對象返回false。

t3結果無論如何都不會相等的,因為new Integer(120)構造器會創建新的對象。

Byte、Short、Integer、Long、Char這幾個裝箱類的valueOf()方法都會做緩存,而Float、Double則不會,原因也很簡單,因為byte、Short、integer、long、char在某個範圍內的整數個數是有限的,但是float、double這兩個浮點數卻不是。

java基本類型與引用類型