Ch.10 陣列

10-1 一維陣列

假設在一個程式中,您要儲存 10 個人的年齡,如果您只學過簡單的變數宣告,在您的想法中應該建立個別的變數來記錄這十個值。舉例來說:

int
int
int
int
int
int
int
ageOne = 27;
ageTwo = 12;
ageThree = 82;
ageFour = 70;
ageFive = 54;
ageSix = 6;
ageSeven = 1;
int ageEight = 30;
int ageNine = 34;
int ageTen = 42;
                            

如果您需要儲存 1,000 個或是 10,000 個年齡呢?當變數的數目增加時,光是撰寫變數宣告就足以讓您花上半天的時間,且程式變得難以處理及冗長。

Java 程式語言可以讓您利用一維陣列( One-dimensional arrays ),把多個相同型態( Type )的變數聚集起來。當您擁有一堆相關的資料(就如同數個人的年齡),陣列就很有用,您不再需要建立個別的變數來儲存每一個資料。

• 宣告一維陣列參考

陣列在 Java 中實際上是一個物件,對於任何物件,您必須宣告一個參考名稱以參考至物件,底下為宣告一維陣列參考的語法:

type[] array_identifier;
                            

其中:

  • type 表示儲存在陣列中的值為基本資料型態或是物件型態。
  • [] 用來告知編譯器,您所宣告的是一維陣列參考。
  • array_identifier 是您指派給陣列的名稱。

舉個實例來看,以下的程式碼為宣告一個名為 status 的 char 一維陣列,及一個名為 ages 的 int 一維陣列

char[] status;
int[] ages;
                            

以下的程式碼宣告了一個名為 score 的 Integer 陣列:

Integer[] scores;
                            

[] 可以出現在陣列名稱的後面。如: type array_identifier[],這種寫法是延續自 C/C++的陣列宣告語法,在 Java 中比較鼓勵的語法是將[]放在型態關鍵字的後面。

當您宣告一個陣列參考名稱時,編譯器及 JVM 並不知道陣列的大小,您只是宣告一個名稱,這個名稱尚未參考至任何的陣列物件。

• 實例化一維陣列

您可以使用 new 關鍵字來建立一維陣列,建立時必須指定陣列的長度,實例化陣列物件的語法為:

其中:

  • array_identifier 是您宣告的一維陣列參考名稱。
  • type 用來表示儲存在陣列中的元素之所屬型態。
  • length 用來表示陣列的大小(元素的數目)。

以下的程式碼用來建立一維 char 陣列與一維 int 陣列,並分別指定給 status 與 ages 一維陣列參考名稱:

status = new char[20];
ages = new int[5];
                            

以下的程式碼用來建立一維 Integer 陣列實例,並指定給score 名稱參考:

scores = new Integer[5];
                            

陣列中的每一個成員稱為元素( Element )。如果您宣告一個大小為 100 的 int 型態陣列,則有 100 個元素。當您實體化陣列物件時,每一個元素都會被初始化為您所指定之型態的預設初始值,如表 10-1 所示:

資料型態初始值
byte0
short0
int0
long0L
float0.0F
double0.0D
char\u0000
booleanfalse
Objectnull
表 10-1 陣列元素初始值

\u0000 為 Unicode 字元集中的空字元,而對於物件陣列,例如之前所宣告的 scores 陣列,陣列中每一個元素的初始值都是 null,也就是每一個元素都可看作一個參考名稱,而目前所有元素都還沒參考至物件實例。

圖10-1 陣列的元素的預設初值

• 存取一維陣列元素

陣列中的每一個特定元素,可以透過它在陣列中的位置或是索引( Index )來存取,設定特定值給陣列元素的語法如下:

array_identifier[index] = value;
                            

其中:

  • array_identifier 是陣列的名稱。
  • index 表示該值將被放置在陣列中的位置。
  • value 為要指派至陣列 index 位置的值。

您可以在指定運算子( Assignment operator )的右側放置陣列的名稱及索引值(放在括弧中[ ])來取得陣列的值,以下是從陣列中取出值的程式範例:

char s = status[0];
int age = ages[1];
Integer score = scores[2];
                            

以下則是設定陣列之元素值的程式範例:

status[0] = '3';
ages[1] = 19;
scores[2] = new Integer(10);
                            

必須特別注意的是,陣列的索引值是從 0 開始,如果陣列長度是 5,則第一個元素是在索引 0 的位置,最後一個元素是在索引 4 的位置。

索引值從 0 開始是有原因的,其背後意義為所指定的陣列元素相對於陣列第一個元素記憶體位置的位移量( Offset )。

程式碼 10-1 示範了如何宣告一維陣列參考、實例化一維陣列、顯示陣列元素初值,並示範了如何使用索引指定來存取陣列元素。

public class OneDimArray{
    public static void main(String[] args){
        char[] status = new char[4];
        int[] ages = new int[2];

        System.out.println("陣列元素初值:");
        System.out.print("status: " + status[0]);
        System.out.print(" " + status[1]);
        System.out.print(" " + status[2]);
        System.out.println(" " + status[3]);

        System.out.print("ages: " + ages[0]);
        System.out.println(" " + ages[1]);

        status[0] = 'J';
        status[1] = 'a';
        status[2] = 'v';
        status[3] = 'a';

        ages[0] = 1;
        ages[1] = 2;

        System.out.println("\n 設定陣列元素:");
        System.out.print("status: " + status[0]);
        System.out.print(" " + status[1]);
        System.out.print(" " + status[2]);
        System.out.println(" " + status[3]);

        System.out.print("ages: " + ages[0]);
        System.out.println(" " + ages[1]);
    }

}
                            
程式碼 10-1 OneDimArray.java

執行結果如下:

圖10-2 程式碼 10-1 的執行結果

• 宣告、實例化及初始化一維陣列

如果在宣告陣列的時候,您已經知道想在陣列中所存放的值為何,則可以在同一行程式碼中,對陣列進行宣告、實例化及設定初值,以下為結合宣告、實例化及設定值的語法:

type[] array_identifier = {,分隔的值或運算式} ;
                            

其中:

  • type 用來表示儲存在陣列中元素之型態。
  • []用來告知編譯器,此宣告為一維陣列。
  • array_identifier 是所使用的陣列名稱。
  • {,分隔的值或運算式}表示一連串您想要儲存在陣列內的值,或一連串的運算式,這些運算式會將其運算的結果儲存在陣列內。

以下的程式碼結合陣列的宣告、實例化及初始化:

int[] ages = {19, 42, 92, 33, 46};
char[] name = {'J', 'a', 'v', 'a'};
                            

如果是使用類別名稱來宣告陣列,您也可以設定每一個物件的值,只需要利用建構式將參考儲存在陣列中,以下的程式碼示範 Integer 物件陣列的宣告、實例化及初始化:

Integer[] scores = {new Integer(1),new Integer(2), new Integer(3)};
                            

圖10-3 初始化後各元素的值或所參考之物件

程式碼 10-2 示範如何宣告、實例化及初始化一維陣列。

public class OneDimArray2{
    public static void main(String[] args){
        int[] ages = {19, 42, 92, 33, 46};
        char[] name = {'J', 'a', 'v', 'a'};
        Integer[] scores = {new Integer(1),
                new Integer(2),
                new Integer(3)};

        System.out.println("陣列元素初值:");
        System.out.print("ages: " + ages[0]);
        System.out.print(" " + ages[1]);
        System.out.print(" " + ages[2]);
        System.out.print(" " + ages[3]);
        System.out.println(" " + ages[4]);

        System.out.print("name: " + name[0]);
        System.out.print(" " + name[1]);
        System.out.print(" " + name[2]);
        System.out.println(" " + name[3]);

        System.out.print("scores: " +
                scores[0].intValue());
        System.out.print(" " +
                scores[1].intValue());
        System.out.println(" " +
                scores[2].intValue());
    }
}
                            
程式碼 10-2 OneDimArray2.java

您可以看到,對於物件陣列,您可以在指定陣列名稱與索引值之後,直接再加上 . 運算子來操作所參考的物件,執行的結果如圖 10-4 所示:

圖10-4 程式碼 10-2 的執行結果

事實上您也可以在使用 new 關鍵字建立陣列實例時,一併初始化陣列元素:

int[] ages = new int[] {19, 42, 92, 33, 46};
                            

這個語法其實作用類似於以下的寫法:

int[] ages = {19, 42, 92, 33, 46};
                            

• length 屬性

因為您所建立的陣列是物件,所以它們可以擁有自己的屬性及方法的集合,所有的陣列物件都擁有 length 屬性,其代表了陣列的長度。

您可以在陣列名稱之後加上 . 運算子,之後接著 length 屬性來取得陣列的長度值,例如下面的程式碼片段將顯示陣列的長度 5:

int[] ages = {32, 22, 43, 11, 55};
System.out.println(ages.length);
                            

一個陣列的長度也可以視為它的邊界( Bounds )之一,在存取陣列元素時不可以超過它的邊界,由於陣列的索引是從 0 開始,所以最大索引應該是它的長度減去一,舉例來說,如果 ages 陣 列的 長度是 5,則 陣列 的邊界是 ages[0] 與 ages[4],如果您打算存取陣列邊界外的元素,例如您打算存取 ages[5] ,則您將會得到錯誤訊息,程式會丟出 ArrayIndexOutOfBoundsException 例外。

• 使用迴圈存取陣列元素

逐一存取陣列的值是令人厭煩的,因為您需要撰寫每一行程式來存取在陣列中每一個元素。然而您可以使用迴圈來反覆設定陣列中每一個元素的值,以下的例子說明如何利用迴圈來從陣列的開始到結束逐一設定初值。

int[] myArray;
myArray = new int[10];
for(int count = 0; count < myArray.length; count++) {
    myArray[count] = count;
}
                            

這個例子中,每一個在 myArray 中的元素都已經被填入與 count 相同的值,例如:myArray[0]的值為 0,myArray[1]的值為 1,其它依此類推。

程式碼 10-3 示範了如何使用廻圈來設定陣列的元素值,以及如何在下一次迴圈時顯示陣列中所有元素的值。

public class OneDimArray3{
    public static void main(String[] args){
        int[] myArray;
        myArray = new int[10];
        for (int count = 0;
             count < myArray.length;
             count++){
            myArray[count] = count;
        }

        System.out.print("myArray: ");
        for (int count = 0;
             count < myArray.length;
             count++){
            System.out.print(myArray[count] + " ");
        }
        System.out.println();
    }
}
                            
程式碼 10-3 OneDimArray3.java

執行結果如下:

圖10-5 程式碼 10-3 的執行結果

• 使用 foreach 語法取得陣列元素

從 JDK 5.0 開始新增了 foreach 語法,又稱之為 Enhanced for loop,您可以將這個語法使用於陣列的循序存取上,語法如下:

for(type element : array) {
    deal with element;
}
                            
  • type 宣告的元素型態必須與陣列的元素型態相同。
  • array 是您想要循序走訪的元素。
  • 每一次的迴圈,都會將下一個陣列元素設定給 element 。

舉個例子來說,您可以將程式碼 10-3 中的第 12 到 16 行改以foreach 語法來顯示陣列元素。

public class OneDimArray4{
    public static void main(String[] args){
        int[] myArray;
        myArray = new int[10];
        for (int count = 0;
             count < myArray.length;
             count++){
            myArray[count] = count;
        }

        System.out.print("myArray: ");
        for(int element : myArray) {
            System.out.print(element + " ");
        }
        System.out.println();
    }
}
                            
程式碼 10-4 OneDimArray4.java

程式的語法簡潔了許多,而執行結果與程式碼 10-3 是相同的,您可以參考圖 10-5 的畫面。