【Java】Wrapper包裝類 (裝箱與拆箱、包裝類的一些API、包裝類對象的緩存問題)

Wrapper包裝類

1、爲什麼要有包裝類

爲什麼要有包裝類?

因爲Java是面向對象的編程語言,但是Java發明時,是C語言盛行的時候,而且C語言確實很好用。特別是其中的8種基本數據類型,不管在存儲還是運算都很強大,那麼,Java就延續使用了C語言的8種基本數據類型。

Java語言是一個面向對象的語言,但是Java中的基本數據類型卻是不面向對象的。基本數據類型有它的優勢:性能(效率高,節省空間)。
但是我們在實際使用中經常需要將基本數據類型轉化成對象,便於操作。比如:

(1)集合的操作,

(2)使用Object類型接收任意類型的數據等,

(3)泛型實參,

Java後面在設計很多的API、新的特性(泛型等),這些都不支持基本數據類型,只支持對象。這時,我們就需要將基本數據類型數據轉化爲對象,爲這8種基本數據類型配上包裝類。

8種基本數據類型不屬於對象。

需要經常將基本數據類型轉化爲對象,便於操作。

爲對象而設計包裝類。

2、包裝類

當要使用只針對對象設計的API或新特性(例如泛型),那麼基本數據類型的數據就需要用包裝類來包裝。

序號 基本數據類型 包裝類
1 byte Byte
2 short Short
3 int Integer
4 long Long
5 float Float
6 double Double
7 char Character
8 boolean Boolean
9 void Void

基本數據類型 包裝類(java.lang)

3、 裝箱與拆箱

JDK讓程序員更簡潔的去操作包裝類,在JDK1.5引入了自動裝箱與自動拆箱。在這個之前需要手動裝箱與拆箱。

裝箱:把基本數據類型的數據 包裝 稱爲包裝類的對象

基本數據類型 -->包裝類的對象

把基本數據類型轉爲包裝類對象。

轉爲包裝類的對象,是爲了使用專門爲對象設計的API和特性

拆箱:把包裝類的對象 拆解 稱爲基本數據類型的數據

包裝類的對象 -->基本數據類型

把包裝類對象拆爲基本數據類型。

轉爲基本數據類型,一般是因爲需要運算,Java中的大多數運算符是爲基本數據類型設計的。比較、算術等

手動裝箱

 @Test
    public void test1(){
        //裝箱操作
        int a = 10;//a是基本數據類型
        Integer aObj = new Integer(a);//把a中的數據,包裝成一個對象

        System.out.println(a);
        System.out.println(aObj);//自動調用toString(),Integer重寫了Object的toString,打印的是包裝的值

        System.out.println(aObj.getClass());//運行時類型
        System.out.println(aObj.hashCode());
        //Result
        //10
        //10
        //class java.lang.Integer
        //10
    }

自動裝箱:當把基本數據類型的值,賦值給包裝類的變量時,就會自動裝箱。

(auto_boxing)

自動拆箱:把包裝類的對象賦值給對應的基本數據類型的變量時,就會自動拆箱(unboxing)

自動裝箱

 @Test
    public void test2(){
        //裝箱操作
        int a = 10;//a是基本數據類型
        Integer aObj = a;//左邊是包裝類型,右邊是int類型    自動裝箱
        System.out.println(aObj.getClass());
    }

注意:只能與自己對應的類型之間才能實現自動裝箱與拆箱。

Integer i = 1;
Double d = 1;//錯誤的,1是int類型
@Test
    public void test3(){
        int a = 10;
//		Double d = a;//因爲Double不是int的包裝類,
//		Double d = 10;//因爲Double不是int的包裝類,
        Double d = 10.0;//Double包裝類只能與double類型的數據自動裝與拆
    }

 @Test
    public void test4(){
        Integer i = new Integer(10);

        int a = i.intValue();//手動拆箱
        int b = i;//自動拆箱
    }
 @Test
    public void test5(){
        Integer i = new Integer(1);
        int j = 1;

        System.out.println(i == j);//(1)先把i拆箱爲int值(2)然後int與int比較
        //true
    }
 @Test
    public void test6(){
        Integer i = new Integer(1);
        double j = 1.0;

        System.out.println(i == j);//(1)先把i拆箱爲int值(2)然後把i自動類型轉換爲double(3)然後比較
        //一旦變爲基本數據類型,那麼就要考慮基本數據類型的自動類型轉換或強制類型轉換的問題了。
        //自動類型轉換 包裝類拆箱
    }

總結:對象(引用數據類型)能用的運算符有哪些?

(1)instanceof

(2)=:賦值運算符

(3)==和!=:用於比較地址,但是要求左右兩邊對象的類型一致或者是有父子類繼承關係。

(4)對於字符串這一種特殊的對象,支持“+”,表示拼接。

4、 包裝類的一些API

1、基本數據類型和字符串之間的轉換

(1)把基本數據類型轉爲字符串

int a = 10;
//String str = a;//錯誤的
//方式一:
String str = a + "";
//方式二:
String str = String.valueOf(a);

(2)把字符串轉爲基本數據類型

通過包裝類的parseXxx(String s)靜態方法

int a = Integer.parseInt("整數的字符串");
double a = Double.parseDouble("小數的字符串");
boolean b = Boolean.parseBoolean("true或false");
@Test
    public void test17(){
        int a = Integer.parseInt("1314");
        System.out.println(a);//1314
        double d = Double.parseDouble("123.456");
        System.out.println(d);//123.456
        boolean b = Boolean.parseBoolean("true");
        System.out.println(b);//true
    }
@Test
    public void test7(){
        //Integer
        int num1 = Integer.parseInt("123");//把字符串類型的"123"轉爲int類型
        System.out.println(num1);//123

//		int num2 = Integer.parseInt("123.05");//錯誤,報NumberFormatException
//		System.out.println(num2);
        //Double
        double num2 = Double.parseDouble("123.05");
        System.out.println(num2);//123.05
    }

先轉成Integer對象,後拆箱爲int

 @Test
    public void test8(){
        int num1 = Integer.valueOf("123");//兩邊,先轉成Integer對象,後拆箱爲int

        double d = Double.valueOf("125.05");
    }

2、數據類型的最大最小值

MIN_VALUE、MAX_VALUE
Float和Double中還有正無窮大POSITIVE_INFINITY、負無窮大NEGATIVE_INFINITY,還NaN,是Not a Number的縮寫。NaN 用於處理計算中出現的錯誤情況,比如 0.0 除以 0.0 或者求負數的平方根。
程序員可以利用這種定製的 NaN 值中的特定位模式來表達某些診斷信息。

常量值

Integer.MAX_VALUE和Integer.MIN_VALUE
Long.MAX_VALUE和Long.MIN_VALUE
Double.MAX_VALUE和Double.MIN_VALUE
 @Test
    public void test10(){
        System.out.println(Byte.MAX_VALUE);//127
        System.out.println(Byte.MIN_VALUE);//-128

        System.out.println(Integer.MAX_VALUE);//2147483647
        System.out.println(Integer.MIN_VALUE);//-2147483648

        System.out.println(Long.MAX_VALUE);//9223372036854775807
        System.out.println(Long.MIN_VALUE);//-9223372036854775808

        System.out.println(Double.MAX_VALUE);//1.7976931348623157E308
        System.out.println(Double.MIN_VALUE);//4.9E-324

    }

3、轉大小寫

轉大小寫:Character

Character.toUpperCase('x');
Character.toLowerCase('X');
 @Test
    public void test11(){
        System.out.println(Character.toUpperCase('a'));//A
        System.out.println(Character.toLowerCase('T'));//t
    }

4、轉進制

Integer.toBinaryString(int i) 
Integer.toHexString(int i)
Integer.toOctalString(int i)
@Test
    public void test9(){
        System.out.println(Integer.toBinaryString(10));//轉爲二進制
        //1010
        System.out.println(Integer.toOctalString(10));//轉爲八進制
        //12
        System.out.println(Integer.toHexString(10));//轉爲十六進制
        //a
    }

5、 包裝類對象的緩存問題

我們在編程時大量需要值在-128到127範圍之間的Integer對象。如果只能通過new來創建,需要在堆中開闢大量值一樣的Integer對象。這是相當不划算的,IntegerCache.cache很好的起到了緩存的作用。

包裝類對象的緩存問題

自動裝箱這種情況。

Byte,Short,Integer,Long:都有緩存對象 -128~127

Float,Double沒有緩存對象

Character:0~127 最早的ASCII碼錶的128個字符

Boolean:false,true

包裝類 緩存對象
Byte -128~127
Short -128~127
Integer -128~127
Long -128~127
Float 沒有
Double 沒有
Character 0~127
Boolean true和false
Integer i = 1;
Integer j = 1;
System.out.println(i == j);//true

Integer i = 128;
Integer j = 128;
System.out.println(i == j);//false

Integer i = new Integer(1);//新new的在堆中
Integer j = 1;//這個用的是緩衝的常量對象,在方法區
System.out.println(i == j);//false

Integer i = new Integer(1);//新new的在堆中
Integer j = new Integer(1);//另一個新new的在堆中
System.out.println(i == j);//false

Integer i = new Integer(1);
int j = 1;
System.out.println(i == j);//true,凡是和基本數據類型比較,都會先拆箱,按照基本數據類型的規則比較
@Test
    public void test13(){
        //自動裝箱
        Integer a = 1;
        Integer b = 1;
        System.out.println(a == b);//true    a == b比較的也是地址值     a和b指向的是同一個緩存的常量對象


        Integer c = 130;
        Integer d = 130;
        System.out.println(c == d);//false  c == d比較的也是地址值    c和d都是在堆中新建的Integer對象
    }
   @Test
    public void test14(){
        Integer a = 1;
        Double b = 1.0;
        Long c = 1L;
        long d = 1L;

//		System.out.println(a == b);//無法比較,因爲對象比較地址,必須是同一種類型或有父子類關係
//		System.out.println(a == c);//無法比較,因爲對象比較地址,必須是同一種類型或有父子類關係

        System.out.println(a == d);//true //因爲d是基本數據類型,a纔會自動拆箱
    }
 @Test
    public void test15(){
        Double d1 = 1.0;
        Double d2 = 1.0;
        System.out.println(d1 == d2);//false
    }
@Test
    public void test16(){
        Character c1 = '0';//ASCII碼,Unicode碼:48
        Character c2 = '0';
        System.out.println(c1 == c2);//true

        //Character:0~127   最早的ASCII碼錶的128個字符
        Character c3 = '菜';
        Character c4 = '菜';
        System.out.println(c3 == c4);//false
    }

6、參考資料

記錄 - 搞定Java核心技術

從Hello到goodbye

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章