java基本型別與引用型別
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.物件相等比較時
先來看一個常見的例子:
nteger 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這兩個浮點數卻不是。
原文:https://blog.csdn.net/chengbinbbs/article/details/78973453