Ch.8 建立、使用物件

8-1 Wrapper 類別

Java 程式語言是一個支援物件導向模型來撰寫程式的語言,即使是一個最基本的 Java 程式(例如顯示"Hello!World"的程式)也是以定義類別( Class )開始,在 Java 程式設計中「幾乎」所有的元素都是物件( Object ),用「幾乎」來形容的原因是因為基本資料型態( Primitive data type )不是物件,也就是使用 byte、short、int、long、float、long、boolean 等關鍵字宣告的變數並不是物件。有幾個常見的問題需要先回答!

學習物件導向程式設計的第一步就是了解如何使用物件,而在 Java 程式語言中您必須知道物件與基本資料型態的差別在哪?在這個小節中,藉由以下幾個重點來讓您了解它們的差異:

  • 認識、使用 Wrapper 類別
  • 變數與參考的差別

• 認識、使用 Wrapper 類別

在 Java 中有著各種資料型態,例如 byte、short、int、long、float、long、char、boolean 等,程式運行過程中每一個資料型態基本型態會依其型態佔有不同的記憶體空間,並代表一個整數、浮點數、布林值等資料,選擇正確的資料型態不僅可以節省程式運行時所需的記憶體空間,更可以加速程式執行的效率。

圖8-1 為程式中的每一份資料選擇正確的資料型態

如果您需要一個空間來儲存資料,您需要告訴編輯器該空間將儲存的資料型態,以及您將用哪一個名稱來取得該空間的資料,編譯器會為您保留適當的記憶體空間以供您儲存資料。

圖8-2 宣告變數在於保留記憶體空間與一個適當的名稱

在 Java 中可以使用 byte、short、int、long、float、long、char、boolean 等來宣告一個基本型態變數,例如宣告一個int 整數型態的變數:

int ageOfStudent = 20;
                            

接下來您就可以使用 ageOfStudent 這個變數名稱來儲存資料,或是將資料取出以供運算,然而除了數值本身之外,不帶有任何的資訊,您要自己記得一些細節,例如記得它是個int 整數型態,而您也無法在數值上直接操作,例如要求它自己與另一個數值進行比較。

圖8-3 基本資料型態所攜帶的資訊是相當有限的

Java 是以物件導向為中心的程式語言,簡單的說,物件可以攜帶比基本資料型態更多的資訊,您也可以直接對物件進行一些操作,為了從基本資料型態上獲得更多的訊息,您可以使用 Java SE 所提供的標準 Wrapper 類別來包裝基本資料型態,表 8-1 列出與基本資料型態相對應的 Wrapper 類別。

基本資料型態Wrapper 類別
bytejava.lang.Byte
shortjava.lang.Short
intjava.lang.Integer
longjava.lang.Long
floatjava.lang.Float
doublejava.lang.Double
charjava.lang.Character
booleanjava.lang.Boolean
表 8-1 基本資料型態與對應的 Wrapper 類別

Wrapper 類別會以您所提供的數值為基礎,每當您要求某個額外資訊或操作時,它就以您所提供的數值作運算,並將運算結果提供給您,至於運算的細節您不用理會,因為 Java SE 所提供的類別都是有經驗的開發人員所撰寫而成,您可以信任他們所撰寫的類別,輕鬆取得所需的訊息。

來看看使用 Wrapper 類別的例子,您可以將 int 整數 20 包裝為 Integer 物件,方法如下:

Integer ageOfStudent = new Integer(20);
                            

您使用 Integer 宣告一個參考名稱 ageOfStudent,並使用 new 表示新建一個物件,建立物件時您必須提供一個 int 整數,以作為 Wrapper 物件運算的基礎。

重點提示

Integer 類別的完整名稱應該是 java.lang.Integer,不過 java.lang 是常用套件(package),對於 java.lang 下的類別都所以可以省略這個部份,編譯器會自動將 java.lang 與 Integer 名稱連結在一起以完成編譯。

在建立 一個 Wrapper 物件之後,接下來就可以操作該Wrapper 物件上所定義的各項操作,操作方式是使用 . 運算子加上方法( Method )名稱,表 8-2 先列出幾個基本的操作:

方法名稱作用
byteValue()將 Wrapper 的資料以 byte 型態傳回
doubleValue()將 Wrapper 的資料以 double 型態傳回
floatValue()將 Wrapper 的資料以 float 型態傳回
intValue()將 Wrapper 的資料以 int 型態傳回
longValue()將 Wrapper 的資料以 long 型態傳回
compareTo(Integer anotherInteger)與另一個 Integer 物件比較大小,傳回 0 表示相等,傳回 -1 表示小於anotherInteger,傳回 1 表示大於 anotherInteger
表 8-2 幾個 Integer 類別上可操作的方法

直接來看個程式撰寫實例,了解如何使用 Wrapper 類別。

public class WrapperDemo{
    public static void main(String[] args){
        Integer ageOfStudent = new Integer(20);

        System.out.print("原來的 int 值:");
        System.out.print("double 型態:");
        System.out.println(
                ageOfStudent.intValue());
        System.out.println(
                ageOfStudent.doubleValue());

        Integer ageOfOther = new Integer(10);

        int result =
                ageOfStudent.compareTo(ageOfOther);
        System.out.print("ageOfStudent");
        switch (result){
            case 1:
                System.out.print(" 大於 ");
                break;
            case -1:
                System.out.print(" 小於 ");
                break;
            case 0:
                System.out.print(" 等於 ");
                break;
        }
        System.out.println("ageOfOther");
    }
}
                            
程式碼 8-1 WrapperDemo.java

這個程式主要的目的是示範如何建立與操作 Wrapper 物件,在程式的第 7、10 與 15 行分別操作了 intValue()、doubleValue()與 compareTo()方法,您不必使用強制型態轉換 ( Casting ) 就可以取得對應的資料型態,而由於compareTo()可以傳回整數值,所以可使用 switch 結構來進行判斷該顯示"大於"、"小於"或"等於",程式的執行結果如圖8-4 所示:

圖8-4 程式碼 8-1 的執行結果

重點提示

在未來學習 Java 的過程中,您會學習到物件容器 ( Container ) 的 使 用(像是 java.util.ArrayList 、java.util.HashMap 等),儲存至物件容器的資料必須是物件,如果您要將數值儲存至這些容器中,您也必須使用 Wrapper 類別先加以包裝。

圖8-5 物件會帶有更多的資訊與操作

• 變數與參考的差別

當您需要在程式中儲存一個數值時,您可以使用 byte、short、int、long、float、long、char、boolean 等宣告變數,這讓編譯器為您保留一個記憶體空間,您可以使用所宣告的變數名稱來取得該空間的值,或是將數值儲存至該空間中。

當您需要一個物件時,您使用 new 關鍵字加上類別名稱來建立,例如以下建立一個 Integer 型態的物件:

new Integer(10);
                            

物件建立之後會存在記憶體中的某處,您要有一個方式來操作物件上的方法(Method),作法是使用類別來宣告一個名稱並指定物件給它,該名稱叫作參考(Reference)名稱,例如:

Integer iRef = new Integer(10);
                            

現在您要思考一個問題,上面的宣告中 iRef 與下面的宣告中 iVar,兩個名稱有什麼分別?

int iVar = 10;
                            

主要的差別是,當您指定數值給 iVar 時,數值於記憶體中儲存的位置是固定的,所以當您重新指定值給 iVar 時,原來空間中的數值就被覆蓋掉了,例如:

iVar = 20;
                            

圖8-6 重新指定值表示原來空間中的值被覆蓋

然而 iRef 是個參考名稱,它用來參考至( Refer to )物件所在的記憶體空間,所以當您重新指定物件給 iRef 參考時,原來 iRef 所參考的物件並不會被覆蓋,例如:

iRef = new Integer(20);
                            

圖8-7 iRef 只是參考至另一個物件

您可以將參考名稱想像為一個標籤,這個名稱可以繫在 A 物件上,您也可以將該標籤繫至 B 物件上,當您使用參考名稱操作物件時,真正所操作的是標籤當時所繫結的物件。

當您將某個變數指定給另一個變數時,右邊變數的值會複製一份來覆蓋左邊變數的值,例如:

int iVar1 = 10;
int iVar2 = 20;
iVar1 = iVar2;
                            

在以上的指定中,iVar1 記憶體空間的值原來是 10,後來被所複製的 20 所覆蓋了,所以 iVar1 的記憶體空間會儲存 20 的值。

然而如果您將某個參考名稱所參考的物件指定給另一個參考名稱,結果會導致兩個參考名稱參考至同一個物件,例如:

Integer iRef1 = new Integer(10);
Integer iRef2 = new Integer(20);
iRef1 = iRef2;
                            

圖8-8 兩個名稱參考至同一物件

重點提示

Java 有自動垃圾回收機制,如果沒有任何的名稱參考至某個物件,則在適當的時機該物件會被 Java 執行環境回收,以釋放物件所佔據的資源。