操作陣列物件


如果事先不知道元素值,只知道元素個數,那可以使用new關鍵字指定長度來建立陣列。例如預先建立長度為10的陣列:

int[] scores = new int[10];

在Java中只要看到new,一定就是建立物件,這個語法代表了陣列就是物件。使用new建立陣列後,每個索引元素會有預設值,如下表所示:

型態 初始值
byte
0
short 0
int
0
long
0L
float
0.0F
double
0.0D
char
\u0000(空字元)
boolean
false
類別 null

如果預設初始值不符合你的需求,你可以使用java.util.Arraysfill()方法來設定新建陣列的元素值。例如將每個學生的成績預設為60分起跳:

package cc.openhome;

import java.util.Arrays;

public class Score2 {
    public static void main(String[] args) {
        int[] scores = new int[10];
        for(int score : scores) {
            System.out.printf("%2d", score);
        }
        System.out.println();
        Arrays.fill(scores, 60);
        for(int score : scores) {
            System.out.printf("%3d", score);
        }
    }
}

執行結果如下:

0 0 0 0 0 0 0 0 0 0
60 60 60 60 60 60 60 60 60 60

如果想在new陣列時一併指定初始值,可以如下撰寫,注意不必指定陣列長度:

int[] scores = new int[] {88, 81, 74, 68, 78, 76, 77, 85, 95, 93};

陣列既然是物件,在本章一開始你也知道,物件是根據類別而建立的實例,代表建立陣列物件的類別定義在哪?答案是由JVM動態產生。某種程度上,你可以將int[]這樣的寫法,看作是類別名稱,這麼看待之後,根據int[]而宣告的變數就是參考名稱了,來看看以下這個片段會顯示什麼?

int[] scores1 = {88, 81, 74, 68, 78, 76, 77, 85, 95, 93};
int[] scores2 = scores1;
scores2[0] = 99;
System.out.println(scores1[0]);

因為陣列是物件,而scores1scores2是參考名稱,你將scores1指定給scores2,意思就是將scores1參考的物件也給scores2參考,第二行執行後,以圖來表示就是:

一維陣列物件與參考名稱


scores2[0] = 99的意思是,將scores2參考的陣列物件索引0指定為99,而顯示時使用scores1[0]的意思是,取得scores1參考的陣列物件索引0的值,結果就是99。

瞭解陣列是物件,以及int[]之類宣告的變數就是參考名稱之後,來進一步看二維陣列。如果想用new建立二維陣列,則可以如下:

int[][] cords = new int[2][3];

如果一些書籍常用的說法來說,這建立了2乘3的陣列,每個索引的預設值如上頭表格所示,但是這只是簡化的說法。這個語法實際上建立了一個int[][]型態的物件,裏頭有2個int[]型態的索引,分別參考至長度為3的一維陣列物件,初始值都是0,用圖來表示會更清楚:

二維陣列物件與參考名稱


如果你將int[][] cords,看成是int[][] cordsint[]就相當於一個型態X,實際上你就是在宣告X的一維陣列,也就是X[],也就是說,實際上,Java中的多維陣列基本上都是由一維陣列模擬。

如果使用cords.length取得長度,這其實是取得cords參考的物件有幾個索引?答案是2個。如果我問cords[0].length呢?這是在問cords參考的物件索引0所參考物件(上圖右上的物件)長度為何?答案就是3。同理,如果我問cords[1].length值為何?這是在問cords參考的物件索引1所參考物件(上圖右下的物件)長度為何?答案也是3。回顧一下 陣列基礎XY類別範例,你應該可以知道為何要如下走訪兩維陣列了:

for(int x = 0; x < cords.length; x++) {
    for(int y = 0; y < cords[x].length; y++) {
        System.out.printf("%2d", cords[x][y]);
    }
    System.out.println();
}
   
那麼這段增強式for語法是怎麼回事呢?

for(int[] row : cords) {
    for(int value : row) {
        System.out.printf("%2d", value);
    }
    System.out.println();
}

根據上圖,你應該就知道實際上row參考到的物件就是一維陣列物件。外層for迴圈就是循序取得cords參考物件的每個索引,將參考到的物件指定給int[]型態的row名稱。

如果使用new配置二維陣列後想要一併指定初值,則可以如下撰寫:

int[][] cords = new int[][] {
    {1, 2, 3},
    {4, 5, 6}
};

再試著用圖來表示這段程式碼執行後的結果:

宣告二維陣列物件與初始值


沒有人規定二維陣列一定得是方陣,你也可以建立不規則陣列。例如:

package cc.openhome;

public class IrregularArray {
    public static void main(String[] args) {
        int[][] arr = new int[2][];
        arr[0] = new int[] {1, 2, 3, 4, 5};
        arr[1] = new int[] {1, 2, 3};
        for(int[] row : arr) {
            for(int value : row) {
                System.out.printf("%2d", value);
            }
            System.out.println();
        }
    }
}

範例中new int[2][]僅提供第一個[]數值,這表示arr參考的物件會有兩個索引,但暫時參考至null,如下圖所示:

不規則陣列示意圖之一


接著分別讓arr[0]參考至長度為5,而元素值為1、2、3、4、5的陣列,以及arr[0]參考至長度為3,而元素值為1、2、3的陣列,如下圖所示:

不規則陣列示意圖之二


所以這個範例的執行結果如下:

1 2 3 4 5
1 2 3

所以,這麼建立陣列也是合法的:

int[][] arr = {
    {1, 2, 3, 4, 5},
    {1, 2, 3}
};

以上都是示範基本型態建立的陣列,接下來介紹類別型態建立的陣列。首先看到如何用new關鍵字建立Integer陣列:

Integer[] scores = new Integer[3];

看來沒什麼,只不過型態關鍵字從int、double等換為類別名稱罷了,那麼請問,上面這個片段建立了幾個Integer物件呢?注意!不是3個,是0個!回頭看一下上面的表格,如果是類別型態,這個片段的寫法建立的陣列,每個索引都是參考至null,以圖來表示就是:

類別型態建立的一維陣列


每個索引其實都是Integer型態,可以讓你參考至Integer實例。例如:

package cc.openhome;
public class IntegerArray {
    public static void main(String[] args) {
        Integer[] scores = new Integer[3];
        for(Integer score : scores) {
            System.out.println(score);
        }
        scores[0] = new Integer(99);
        scores[1] = new Integer(87);
        scores[2] = new Integer(66);
        for(Integer score : scores) {
            System.out.println(score);
        }
    }
}

執行結果如下所示:
null
null
null
99
87
66

範例中使用new來建立Integer實例,是為了清楚表示每個索引可參考至Integer實例,其實上面這個範例也可以結合自動裝箱語法,會更簡潔:

scores[0] = 99;
scores[1] = 87;
scores[2] = 66;

將這個片段取代範例中指定索引的部份,執行結果是不變的,如果事先知道Integer陣列每個元素要放什麼,可以如下:

Integer[] scores = {new Integer(99), new Integer(87), new Integer(66)};

如果是JDK5以上,不結合自動裝箱來簡化程式撰寫,就有點可惜了,因為可以少打很多字:

Integer[] scores = {99, 87, 66};

那麼再來問最後一個問題,以下Integer二維陣列,建立了幾個Integer實例?

Integer[][] cords = new Integer[3][2];

應該不會回答6個吧!?對初學者來說,建議試著畫圖來表示:

類別型態建立的二維陣列


new  Integer[3][2]代表著一個Integer[][]型態的物件,裏頭有3個Integer[]型態的索引,分別參考至長度為2的Integer一維陣列物件,而每個Integer一維陣列的索引都參考至null,所以答案還是0個Integer實例。