天天看點

JAVA的包裝類型

最近因工作繁忙,到時将部落格落下,實在慚愧,剛好最近整理了一些資料,看最近有空陸續上傳吧

這次來講解一下java的包裝類型和引用類型,算是對上次的補充吧

一、包裝類

包裝類本質為了解決java基本資料類型不面向對象的不足,于是設計類時為每個基本資料類型都設計了一個對應的包裝類,其各自基本資料類型對于包裝類如下圖:

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

基本類型和包裝類型的差別:

(1)包裝類是引用傳遞 而基本類型是值傳遞;

(2)包裝類是對象,擁有方法和字段,對象的調用都是通過引用對象的位址 ;

(3)初始值不同,基本資料類型如int 的初始值為0,而包裝類型Integer初始值為null;

(4)變量的值存儲在堆棧裡,而對象是存儲在堆裡,相比而言,堆棧更高效,這也是java保留基本類型的原因。

講完差別,來講講為什麼要使用包裝類:

(1)集合不允許存放基本資料類型,是以可以使用包裝類來代替基本資料類型進行操作;

(2)将一些有關這些基本資料類型的參數封裝在相應的對象裡,例如最大值、最小值等,以及對相關的操作方法。

二、包裝類與基本資料類型的轉換

包裝類與基本資料類型的互相轉換如下圖所示:

包裝類 包裝類轉基本類型 基本類型轉包裝類
Byte Byte.valueOf(byte) byteInstance.byteValue()
Short Short.valueOf(short) shortInstance.shortValue()
Integer Integer.valueOf(int) integerInstance.intValue()
Long Long.valueOf(long) longInstance.longValue()
Float Float.valueOf(float) floatInstance.floatValue()
Double Double.valueOf(double) doubleInstance.doubleValue()
Character Character.valueOf(char) charInstance.charValue()
Boolean Boolean.valueOf(booleann) booleanInstance.booleanValue()

 例:

​
int a = 50;
Integer b = Integer.valueOf(a);//基礎資料類型轉包裝類

Integer c = 50;
int d = c.intValue();//包裝類轉基礎資料類型

​
           

 三、自動裝箱和自動拆箱

       在JDK1.5以前,我們不可以直接把基本資料類型指派給引用資料類型 ,建構一個包裝類需要通過構造器來構造包裝類對象,但這樣又過于臃腫,是以從JDK1.5開始就引入了自動裝箱和自動拆箱,系統将自動進行基本資料類型和與之相對應的包裝類型之間的轉換。

Integer a = 50;//自動裝箱,将基礎資料類型打包成包裝類
		
int b = a;//自動拆箱,将成包裝類拆成基礎資料類型
           

注意

Integer a =null;
int b = a;
System.out.println(b);//報空指針
           

這個在編譯時不報錯,但運作時會抛異常,int b = a

實際上是

int b = a.intValue()

,由于a的引用值為null,在空對象上調用方法就會抛出NullPointException。

又來看一個的例子:

Integer a1 = 100;
Integer a2 = 100;
System.out.println(a1==a2);//傳回true

Integer b1 = 200;
Integer b2 = 200;
System.out.println(b1==b2);//傳回false
           

前面我們說了包裝類時引用傳遞,通過位址來調用對象,比較的應該是位址,但第一個又為什麼會傳回true了?這時我們得去看一下Integer的底層了

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

我們說過Integer a = 100實際上是等于Integer a = Integer.valueOf(100),但Integer内置有常量池,從最小-128到最大127都存在常量池,如果你指派的是在這個範圍内的,他會直接從常量池讀取,是以無論指派多少個位址都是一樣的,但一旦超出這個範圍,它就會自己new一個Integer對象來存儲,是以位址才會不同。

還有類似的是String,來看一個例子:

String str1 = "ABC";
String str2 = "ABC";
String str3 =  "AB" + "C";
System.out.println(str1 == str2);//true
System.out.println(str1 == str3);//true
           

String str1 = "ABC" 可能建立一個或不建立對象,這取決于字元串常量池裡是否有“ABC”這個字元,如果”ABC”這個字元串在字元串常量池裡不存在,會在字元串常量池裡建立一個建立一個String對象(“ABC”),然後str1指向這個記憶體位址,無論以後用這種方式建立多少個值為”ABC”的字元串對象,始終隻有一個記憶體位址被配置設定,之後的都是String的拷貝,Java中稱為“字元串駐留”,所有的字元串常量都會在編譯之後自動地駐留。

而String str = new String(“ABC”)則至少建立一個對象,也可能兩個。因為用到new關鍵字,肯定會在堆中建立一個str2的String對象,它的value是“ABC”。同時如果這個字元串再java String池裡不存在,會在java池裡建立這個String對象“ABC”。

tip:String.intern():檢查字元串常量池中是否存在String并傳回池裡的字元串引用;若池中不存在,則将其加入池中,并傳回其引用。 這樣做主要是為了避免在堆中不斷地建立新的字元串對象

四、equals和==的差別

         “==” 符号判斷的記憶體位址所對應的值得相等性,具體來說,基本類型判斷值是否相等,引用類型判斷其指向的位址是否相等。

          “equals”先比較位址是否相同,在比較引用類型位址指向的對象所存儲的内容是否相等。

例如

public boolean equals(Object var1) {
        if (this == var1) {
            return true;
        } else {
            if (var1 instanceof String) {
                String var2 = (String)var1;
                int var3 = this.value.length;
                if (var3 == var2.value.length) {
                    char[] var4 = this.value;
                    char[] var5 = var2.value;

                    for(int var6 = 0; var3-- != 0; ++var6) {
                        if (var4[var6] != var5[var6]) {
                            return false;
                        }
                    }

                    return true;
                }
            }

            return false;
        }
}
           

上面是String的equals源碼,equals是先比較是否同一個對象,再去取出各自對象存儲的值來進行比較,是以在用String進行比較時,最好使用equals方法