Java入門系列之包裝類(四)

前言

上一節我們講解了StringBuilder VS StringBuffer以及二者區別,本節我們來講解包裝類。

包裝類

我們知道在Java中有8中基本數據類型,分為數值類型:byte、short、int、long、float、double。字符類型:char。布爾類型:bool,那麼什麼是包裝類呢?包裝類是8種基本數據類型的對象表示,而且8種包裝類和字符串對象一樣是不可變且final(不可通過繼承或擴展破壞不可變性)的。我們通過查看int的包裝類型Integer可知,如下:

如下為基本數據類型對應的包裝類以及構造函數參數:

基本數據類型包裝類型構造參數
byteBytebyte or String
shortShortshort or String
intIntegerint or String
longLonglong or String
floatFloatfloat, double or String
doubleDoubledouble or String
charCharacterchar
booleanBooleanboolean or String

比如當我們實例化Integer包裝類時,既然是對int的包裝,要是我們傳一個帶小數位的數字,毫無疑問也就拋出如下異常了:

public class Main {

    public static void main(String[] args) {
        Integer a = new Integer("12.5");
    }
}

開頭我們就直接拋出了包裝類的概念,但是不知道您是否有和我一樣的疑惑,我們為什麼要用包裝類呢?比如Integer是對int的包裝,我們直接使用int不就完事了嗎,怎麼還包裝一層呢?這就需要我們瞭解包裝類的作用是什麼了?

1.包裝類將基本數據類型轉換為對象(當我們需要在給定方法中傳遞參數時需要對象)。

2.包java.util只處理對象的類,所以包裝類在這個包中也有其用武之地。

3.數據結構僅存儲對象和基本數據類型。

4.在多線程中,我們需要對象來支持線程同步。

或者説存在即合理,在Java中將包裝類和基本數據類型區分開這是明智之舉,當我們以適合面向對象的方式編程時,我們使用包裝類,當處理起來更加簡單時,我們使用基本數據類型,一切取決於我們。

自動裝箱和拆箱

在Java 5中引入了自動裝箱和拆箱,這允許基本數據類型和包裝類相互之間能夠輕鬆自如的實現轉換。接下來我們通過基本數據類型和包裝類轉換實現裝箱和拆箱,裝箱則是自動將基本數據型轉換為包裝類,拆箱反之。

        char ch = 'a';
        Character a = ch;

        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(25);
        System.out.println(arrayList.get(0));

如上第一個我們將基本數據類型轉換為對象以及我們初始化集合且參數類型為包裝類(對象),緊接着我們在此集合中添加基本數據類型為25的int,都自動實現了裝箱。反過來,如下我們將實現拆箱:

        Character ch = 'a';
        char a = ch;
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(24);
        int num = arrayList.get(0);
        System.out.println(num);

上述我們首先將包裝類轉換為基本數據類型,緊接着我們添加基本數據類型為24的int,這屬於裝箱,但是最後我們獲取數據時賦值給為int的num,也就達到了將包裝類到基本數據類型的轉換,也就是拆箱。同時我們還需謹記:包裝類可以為空,基本數據類型不能為空。也就是説要使其可空,我們必須使用包裝類,這一點比不上C#語法高級,若基本數據類型可空,在C#中可如下定義:

int? a = null;
Console.WriteLine(a == null);

接下來我們來看如下一道題,請問:如下是自動裝箱嗎?如果不是體現了什麼呢?

public class Main {

    public static void main(String[] args) {

        char c = 'a';

        doSomething(new Character(c));
    }

    static void doSomething(Object obj) {

    }

}

我們知道自動裝箱是將基本數據類型轉換為包裝類,上述我們定義了一個doSomething方法,參數為Object類型,在程序入口點,我們調用該方法且傳入的參數為包裝類,所以上述並不是自動裝箱,它所體現的是通過包裝類實現多態。所以我們需謹記:自動裝箱是將基本數據類型轉換為包裝類,而不是將一種數據類型轉換為其他數據類型,這也許就是為什麼自動裝箱不能將String轉換為包裝類的原因。

數據類型轉換

我們依然以基本數據類型int為例,在int對應的包裝類Integer中有intValue方法實現拆箱,比如我們想要將double轉換為int,利用包裝類實現則是如下形式:

        double d = 135.d;
        Double doubleWrapper = new Double(d);
        int integerValue = doubleWrapper.intValue();
        System.out.println(integerValue);

我們也可以使用包裝類類型通過拆箱轉換成其他基本數據類型,當我們需要將基本數據類型轉換為對象並使用它們來獲取其他基本數據類型時,將使用這種類型的轉換。通過如上轉換,我們需要編寫一大片代碼, 然而,我們可以通過如下簡單的方式來實現相同的目的:

        double d = 135.d;
        int integerValue = (int)d; 
        System.out.println(integerValue);

valueOf和parseInt使用詳解

到目前我所知道的有以下兩種方式將String對象轉換為int或Integer,我們一起來看看。

Integer.parseInt

此種方式作為將String轉換為int的首先方式,簡單且靈活,我們看一個例子:

int i = Integer.parseInt("123");
System.out.println("i: " + i);

如果提供的String不是正確的數字,Integer.parseInt()方法將拋出NumberFormatException異常,相同的方式同樣適用於其他數據類型(如float和Double)轉換為Java中的String。 Java API提供靜態方法,如Float.parseFloat()和Double.parseDouble(),以執行數據類型轉換。

Integer.valueOf 

在8種包裝類中都有這個valueOf方法,這也是一種將String轉換為int的方式,我們同樣來看一個示例:

 int i = Integer.valueOf("000000081");
 System.out.println("i: " + i);

它將忽略前導零並將字符串轉換為int。如果提供的String不是正確的數字,同樣也會拋出NumberFormatException異常。在Java 1.4之前沒有自動裝箱,但是在Java 1.5即(Java 5+)引入了自動裝箱,所以推薦使用Integer.valueOf(int)而不是new Integer(int),因為Integer現在可以在-128到127之間緩存Integer對象,並且每次都可以將同一個完整的Integer(0)對象交給我們,而不是在全新的相同Integer對象上浪費對象構造。

下面我們來看兩個例子來驗證上述源碼觀點:

        Integer i1 = 260;
        Integer i2 = 260;
        if (i1 == i2) {
            System.out.println("i1 and i2 is equal");
        } else {
            System.out.println("i1 and i2 is not equal "); }

接下來我們再來看一個例子,如下:

        Integer i1 = 100;
        Integer i2 = 100;
        if (i1 == i2) {
            System.out.println("i1 and i2 is equal");
        } else {
            System.out.println("i1 and i2 is not equal "); }

我們看到“i1和i2相等”,因為-128到127之間的int值在大多數JVM要緩存的範圍內,所以VM實際上對i1和i2使用相同的對象實例(因此也使用同一內存地址),所以打印出相等。Integer.valueOf方法還有重載,我們來看一個例子:

        Integer I = Integer.valueOf("100", 2);
        System.out.println(I);
        Integer i = Integer.valueOf("101", 4);
        System.out.println(i);

第二個參數表示進制,例如上述兩個通過2進製表示100,通過4進製表示101,計算方式如下:

2進製表示100:(1 * 2 ^ 2)+(0 * 2 ^ 1)+(0 * 2 ^ 0)= 4 + 0 + 0 = 4。

4進製表示101:(1 * 4 ^ 2)+(0 * 4 ^ 1)+(1 * 4 ^ 0)= 16 + 0 + 1 = 17。

總結 

valueOf和parseInt方法都用於在Java中將String轉換為Integer,但它們之間存在細微差別(在Java 1.5引入自動裝箱後),我們通過查看valueOf()方法的源碼得知,發現它在內部調用parseInt()方法將String轉換為Integer,但是它還維護一個從-128到127的整數池,如果請求的整數在池中,它從池中返回對象,這也意味着使用valueOf()方法返回的兩個整數對象可以通過相等運算符相同,這種對不可變對象的緩存,確實有助於減少垃圾並幫助垃圾收集器。 parseInt()和valueOf()方法之間的另一個區別是返回類型,valueOf()返回一個Integer對象,而parseInt()方法返回一個int基本數據類型。無論是使用parseInt還是valueOf將String轉換為基本數據類型Int和包裝類Integer,如果我們需要基本數據類型Int可以使用parseInt,由於不可變對象可以安全地緩存在池中並且得到重用,如此一來減少了垃圾收集器的負載,因此如果需要Integer對象,最好使用valueOf。

 

Java中的“==”或等於運算符是Java編程語言提供的二元運算符,用於比較基元和對象,在比較boolean,int,float等基本數據類型時,利用“==”工作正常,但在比較對象時,它會與Java中的equals方法產生混淆, “==”根據內存引用比較兩個對象。 所以“==”運算符只有在兩個對象引用比較時才返回true來表示完全相同的對象,否則“==”將返回false。在Java 5中引入自動裝箱和拆箱之後,因版本的問題使用“==”來比較包裝器對象可能會出現意想不到的結果。

轉載於:https://www.cnblogs.com/CreateMyself/p/11437026.html