# 陣列

> 介紹Java如何宣告、使用陣列，以及記憶體中的配置。

### 什麼是陣列？ What is Array?

陣列是一種由相同型態的資料組成的資料結構。

陣列在記憶體中使用連續的記憶體空間，透過索引值(index)來做資料的存取。

陣列在Java裡是以物件(object)的方式存在，所以陣列本身是參考資料型態(reference type)。

陣列中的元素可以是基本資料型態(primitive type)也可以是參考資料型態(reference type)。

### 陣列的創建 Array Creation

陣列就跟一般的物件一樣，需要透過關鍵字new來創造實體，new後面要有： 1. 元素的資料型態 2. 元素個數

陣列被初始化後，每個元素都會被初始化為該型態的初始值(default value)。

假設我們需要一個大小為3的int陣列，範例程式：

```java
int[] array;  //  宣告
array = new int[3];  // 創建大小為3的int陣列，回傳reference給array
```

當然也可以寫成一行，這是等價的：

```java
int[] array = new int[3];
```

記憶體配置：

![](https://1201963393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLRnhT9aTkN9HvaBP28%2Fsync%2F0a6c271b430950db249fa27b6d97038c8a82133d.jpg?generation=1604653621699679\&alt=media)

### 存取元素 Access Elements

透過陣列名稱，利用中括號『\[ ]』，括號裡面放元素在陣列中的索引值(index)。

**陣列索引值從0開始，只能為非負整數。**

以上圖為例：

```java
int[] array = new int[3];
array[0] = 1;
array[1] = 10;
array[2] = 100;
System.out.println(array[0]);
System.out.println(array[1]);
System.out.println(array[2]);
```

執行結果：

```java
1
10
100
```

### 初始化時給值 Array Initializer

陣列可以同時宣告及指定其值，利用大括號『{ }』，搭配逗號『,』隔開各元素。

```java
int[] array = { 1 , 10 , 100 };
```

編譯器會看大括號理的元素個數及元素值去創造相符的物件，回傳reference給變數array。

這行的效果跟下面相同：

```java
int[] array;
array = new int[3];
array[0] = 1;
array[1] = 10;
array[2] = 100;
```

這種寫法適用於在寫程式的時候已經確定該陣列的元素個數、內容。

### 多維陣列 Multi-Dimensional Array

上面已經討論過一維陣列的宣告及使用，但實務上我們遭遇很多問題並不是單靠一維陣列就可以簡單解決的，因此我們希望可以有一個多維度的陣列來幫我們做處理。

假設我們需要一個大小為2\*3二維的int陣列，範例如下：

```java
int[][] matrix;  // 宣告
matrix = new int[2][3];  // 創件空間，回傳reference給matrix
```

int\[ ]\[ ]是matrix的型態，代表是int的二為陣列，要幾個維度就用幾個『\[ ] 』。

new int\[2]\[3]，創造『大小為2個陣列』，其元素內容為『大小為3的int陣列』。

記憶體配置：

![](https://1201963393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLRnhT9aTkN9HvaBP28%2Fsync%2Fe8d11aa9fd2c876f975fad5c805c87ec6b1083e6.jpg?generation=1604653621908588\&alt=media)

有沒有發現到，Java根本沒有所謂的多維陣列！它只是不斷的在一維陣列中塞另一個陣列！

一個m\*n的二維陣列，就是m個『大小為n的陣列』，更多維度一樣的概念以此類推，這裡只舉二維為例。(不然實在不好畫)

初始化的方法跟一維陣列相同，可以直接寫成程式碼：

```java
int[][] matrix = { {1,2,3} , {5,6,7} };
```

大括號夾起來的就是一個陣列，彼此用逗號『,』隔開，形成陣列中有陣列的樣子。

上述程式效果同於：

```java
int[][] matrix;  // 宣告 matrix 為 int[][] 型態。
matrix = new int[2][];  // matrix 是 『2 個 int[] 的陣列』的陣列
matrix[0] = new int[3]; // matrix[0] 是一個大小為 3 的 int 陣列
matrix[1] = new int[3]; // matrix[1] 是一個大小為 3 的 int 陣列
matrix[0][0] = 1; // 以下幾行利用中括號及索引值設定陣列元素的值
matrix[0][1] = 2;
matrix[0][2] = 3;
matrix[1][0] = 5;
matrix[1][1] = 6;
matrix[1][2] = 7;
```

也因為Java的陣列是這種特性，所以我們也可以創造出『長度不同』的多維陣列。

假設要創造出的陣列長這樣：

![](https://1201963393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLRnhT9aTkN9HvaBP28%2Fsync%2F276996eb2d7c5802a812132768c53e89b665e612.jpg?generation=1604653621314910\&alt=media)

對Java來說，由於陣列在記憶體中都是一維的，不同長度只是指向不同的物件，所以可以輕鬆的初始化。

利用 Initializer ：

```java
int[][] array = { {10,20} , {100} , {5,6,7} };
```

這樣就可以達成要求了！

要一步一步寫的話像這樣：

```java
int[][] array;
array = new int[3][];
array[0] = new int[2];
array[1] = new int[1];
array[2] = new int[3];
array[0][0] = 10;
array[0][1] = 20;
array[1][0] = 100;
array[2][0] = 5;
array[2][1] = 6;
array[2][2] = 7;
```

## 參考型態陣列 Reference Type Array

前面舉的例子是int陣列，而我們知道int是基本資料型態，那如果要創件的是參考資料型態的陣列呢？

恩，就跟創造多維陣列一樣，層層的初始化每個物件。

假設我要創造大小為3的Human陣列： (Human為自訂類別)

```java
Human[] array;  // 宣告 array 為 Human一維陣列
array = new Human[3];  // 創造大小為3的陣列用來存放Human，回傳reference給array
array[0] = new Human();  // array[0]是物件，必須要初始化才能在記憶體中存在。
array[1] = new Human();  // 如果沒有對物件做初始化，預設值為null。
array[2] = new Human();  // 存取null的成員會產生 NullPointerException例外。
```

以上程式可以搭配迴圈使用，是一般常見的做法：

```java
Human[] array = new Human[3];
for(int i=0;i<3;i++)
    array[i] = new Human();
```

記憶體配置：

![](https://1201963393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLRnhT9aTkN9HvaBP28%2Fsync%2Fd6716770a49a41dd6c64be653f3568a03e6ef648.jpg?generation=1604653621474340\&alt=media)

一個最大觀念是，Java的陣列是物件，且都是為一維的陣列。內容可以放值(value)或參考(reference)，因此可以陣列的內容是另一個陣列，創造出多維陣列的感覺。

記憶體的配置圖在陣列的觀念裡面很重要，一定要懂為什麼。如果有什麼不清楚的麻煩讓我知道，或許是文字或圖片沒弄好產生誤解或混淆。

### 陣列長度 length of Array

陣列被創造出來，元素個數就決定好了，很多時候我們需要陣列的大小(length)方便我們做運算、處理，那要如何取得呢？

恩，陣列是一個物件，它有一個資料成員用來紀錄它的大小，就叫做 length。

```java
int[] array = { 1 , 1 , 2 , 3 , 5 , 8 , 13 };
System.out.println(array.length);
```

執行結果：

```java
7
```

利用 `陣列名稱.length` 可以輕鬆取得該陣列的長度，搭配迴圈可以方便的走訪整個陣列：

```java
int[] array = { 1 , 1 , 2 , 3 , 5 , 8 , 13 };
int sum = 0;
for(int i = 0 ; i < array.length ; i++ )
    sum = sum + array[i];
System.out.println("陣列和為："+sum);
```

執行結果：

```java
陣列和為：33
```

### 好用方法 useful Method

簡單介紹幾個常用的方法，很多陣列相關方法都定義在Arrays裡，Arrays放在java.util套件中，使用前別忘了import：

```java
import java.util.Arrays;
```

#### 快速印出所有元素 Arrays.toString(Object\[])

利用這個方法，可以快速的印出陣列中的所有元素，方便自己debug或展示。

```java
int[] array = { 1, 1, 2, 3, 5, 8, 13 };
System.out.println(Arrays.toString(array));
```

執行結果：

```java
[1, 1, 2, 3, 5, 8, 13]
```

#### 複製陣列 .clone()

可以快速的複製一個一模一樣的資料的陣列物件，與原陣列佔用不同記憶體，彼此獨立。

```java
int[] array = { 1, 1, 2, 3, 5, 8, 13 };
int[] array2=array.clone();
array[0]=555;
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(array2));
```

執行結果：

```java
[555, 1, 2, 3, 5, 8, 13]
[1, 1, 2, 3, 5, 8, 13]
```

#### 填滿陣列元素 Arrays.fill(Object\[],value)

可以把陣列全部用value填滿，常用於陣列初始化。

```java
int[] array = new int[10];
System.out.println(Arrays.toString(array));
Arrays.fill(array, -1);  // 以 -1 填滿 array
System.out.println(Arrays.toString(array));
```

執行結果：

```java
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
```

#### 陣列排序 Arrays.sort(Object\[]);

這個方法超美妙的，可以把陣列從小排到大，內部實做是快速排序法(quick sort)，時間複雜度 O(NlogN)，比較的機制是該物件的 .compareTo()方法，實做上可以省掉很多寫排序演算法的時間。

```java
int[] array = {50,1,-999,6000,77,3,50,0};
System.out.println(Arrays.toString(array));
Arrays.sort(array);
System.out.println(Arrays.toString(array));
```

執行結果：

```java
[50, 1, -999, 6000, 77, 3, 50, 0]
[-999, 0, 1, 3, 50, 50, 77, 6000]
```

#### 陣列搜尋 Arrays.binarySearch(Object\[],key)

利用binarySearch搜尋陣列中目標key的索引值，時間複雜度為O(logN)，如果找不到回傳小於0的整數。因為是用binarySearch實做，所以陣列『必須已排序好(遞增)』。

```java
int[] array = {50,1,-999,6000,77,3,50,0};
System.out.println(Arrays.toString(array));
Arrays.sort(array);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.binarySearch(array, 77));
System.out.println(Arrays.binarySearch(array, 2000));
```

執行結果：

```java
[50, 1, -999, 6000, 77, 3, 50, 0]
[-999, 0, 1, 3, 50, 50, 77, 6000]
6    // 77 位在索引值6的位置
-8   // 2000 不存在陣列中
```

#### 陣列相等 Arrays.equals(Object\[],Object\[])

測試兩陣列是否相等，回傳布林值(true or false)。

相等的條件：每個陣列元素的值、順序都完全一樣，若 reference 指到同一物件視為相等，都為 null 也視為相等。

```java
int[] array = { 5, 6, 7 };
int[] array2 = array.clone();
System.out.println(Arrays.equals(array, array2));
array[0] = 1;
System.out.println(Arrays.equals(array, array2));
array = array2;
System.out.println(Arrays.equals(array, array2));
array = null;
array2 = null;
System.out.println(Arrays.equals(array, array2));
```

執行結果：

```java
true   // array2 是 array 複製過來的，所以資料完全一樣，故相等
false  // array變成{1,6,7}，array2還是{5,6,7}，不相等
true   // array 指到 array2的物件，故兩個reference相同，相等
true   // 兩個皆為 null 視為相等
```

其他詳細方法請參考 [document](https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html)。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yubin551.gitbook.io/java-note/basic_java_programming/datatype/array.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
