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

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