:notebook: 本文已歸檔到:「blog」
:keyboard: 本文中的示例程式碼已歸檔到:「javacore」
簡介
陣列的特性
陣列對於每一門程式語言來說都是重要的資料結構之一,當然不同語言對陣列的實現及處理也不盡相同。幾乎所有程式設計語言都支援陣列。
陣列代表一系列物件或者基本資料型別,所有相同的型別都封裝到一起,採用一個統一的識別符號名稱。
陣列的定義和使用需要通過方括號 []
。
Java 中,陣列是一種引用型別。
Java 中,陣列是用來儲存固定大小的同型別元素。
陣列和容器
Java 中,既然有了強大的容器,是不是就不需要陣列了?
答案是不。
誠然,大多數情況下,應該選擇容器儲存資料。
但是,陣列也不是毫無是處:
- Java 中,陣列是一種效率最高的儲存和隨機訪問物件引用序列的方式。陣列的效率要高於容器(如
ArrayList
)。 - 陣列可以持有值型別,而容器則不能(這時,就必須用到包裝類)。
Java 陣列的本質是物件
Java 陣列的本質是物件。它具有 Java 中其他物件的一些基本特點:封裝了一些資料,可以訪問屬性,也可以呼叫方法。所以,陣列是物件。
如果有兩個類 A 和 B,如果 B 繼承(extends)了 A,那麼 A[] 型別的引用就可以指向 B[] 型別的物件。
擴充套件閱讀:Java 中陣列的特性
如果想要論證 Java 陣列本質是物件,不妨一讀這篇文章。
Java 陣列和記憶體
Java 陣列在記憶體中的儲存是這樣的:
陣列物件(這裡可以看成一個指標)儲存在棧中。
陣列元素儲存在堆中。
如下圖所示:只有當 JVM 執行 new String[]
時,才會在堆中開闢相應的記憶體區域。陣列物件 array 可以視為一個指標,指向這塊記憶體的儲存地址。
宣告陣列
宣告陣列變數的語法如下:
int[] arr1; // 推薦風格
int arr2[]; // 效果相同
複製程式碼
建立陣列
Java 語言使用 new
操作符來建立陣列。有兩種建立陣列方式:
- 指定陣列維度
- 為陣列開闢指定大小的陣列維度。
- 如果陣列元素是基礎資料型別,會將每個元素設為預設值;如果是引用型別,元素值為
null
。
- 不指定陣列維度
- 用花括號中的實際元素初始化陣列,陣列大小與元素數相同。
示例 1:
public class ArrayDemo {
public static void main(String[] args) {
int[] array1 = new int[2]; // 指定陣列維度
int[] array2 = new int[] { 1, 2 }; // 不指定陣列維度
System.out.println("array1 size is " + array1.length);
for (int item : array1) {
System.out.println(item);
}
System.out.println("array2 size is " + array1.length);
for (int item : array2) {
System.out.println(item);
}
}
}
// Output:
// array1 size is 2
// 0
// 0
// array2 size is 2
// 1
// 2
複製程式碼
:bulb: 說明 請注意陣列 array1 中的元素雖然沒有初始化,但是 length 和指定的陣列維度是一樣的。這表明指定陣列維度後,無論後面是否初始化陣列中的元素,陣列都已經開闢了相應的記憶體。
陣列 array1 中的元素都被設為預設值。
示例 2:
public class ArrayDemo2 {
static class User {}
public static void main(String[] args) {
User[] array1 = new User[2]; // 指定陣列維度
User[] array2 = new User[] {new User(), new User()}; // 不指定陣列維度
System.out.println("array1: ");
for (User item : array1) {
System.out.println(item);
}
System.out.println("array2: ");
for (User item : array2) {
System.out.println(item);
}
}
}
// Output:
// array1:
// null
// null
// array2:
// io.github.dunwu.javacore.array.ArrayDemo2$User@4141d797
// io.github.dunwu.javacore.array.ArrayDemo2$User@68f7aae2
複製程式碼
:bulb: 說明
請將本例與示例 1 比較,可以發現:如果使用指定陣列維度方式建立陣列,且陣列元素為引用型別,則陣列中的元素元素值為
null
。
陣列維度的形式
建立陣列時,指定的陣列維度可以有多種形式:
- 陣列維度可以是整數、字元。
- 陣列維度可以是整數型、字元型變數。
- 陣列維度可以是計算結果為整數或字元的表示式。
示例:
public class ArrayDemo3 {
public static void main(String[] args) {
int length = 3;
// 放開被注掉的程式碼,編譯器會報錯
// int[] array = new int[4.0];
// int[] array2 = new int["test"];
int[] array3 = new int['a'];
int[] array4 = new int[length];
int[] array5 = new int[length + 2];
int[] array6 = new int['a' + 2];
// int[] array7 = new int[length + 2.1];
System.out.println("array3.length = [" + array3.length + "]");
System.out.println("array4.length = [" + array4.length + "]");
System.out.println("array5.length = [" + array5.length + "]");
System.out.println("array6.length = [" + array6.length + "]");
}
}
// Output:
// array3.length = [97]
// array4.length = [3]
// array5.length = [5]
// array6.length = [99]
複製程式碼
? 說明
當指定的陣列維度是字元時,Java 會將其轉為整數。如字元
a
的 ASCII 碼是 97。綜上,Java 陣列的陣列維度可以是常量、變數、表示式,只要轉換為整數即可。
請留意,有些程式語言則不支援這點,如 C/C++ 語言,只允許陣列維度是常量。
陣列維度的大小
陣列維度並非沒有上限的,如果數值過大,編譯時會報錯。
int[] array = new int[6553612431]; // 陣列維度過大,編譯報錯
複製程式碼
此外,陣列過大,可能會導致棧溢位。
訪問陣列
Java 中,可以通過在 []
中指定下標,訪問陣列元素,下標位置從 0 開始。
public class ArrayDemo4 {
public static void main(String[] args) {
int[] array = {1, 2, 3};
for (int i = 0; i < array.length; i++) {
array[i]++;
System.out.println(String.format("array[%d] = %d", i, array[i]));
}
}
}
// Output:
// array[0] = 2
// array[1] = 3
// array[2] = 4
複製程式碼
? 說明
上面的示例中,從 0 開始,使用下標遍歷陣列 array 的所有元素,為每個元素值加 1 。
陣列的引用
Java 中,陣列型別是一種引用型別。
因此,它可以作為引用,被 Java 函式作為函式入參或返回值。
陣列作為函式入參的示例:
public class ArrayRefDemo {
private static void fun(int[] array) {
for (int i : array) {
System.out.print(i + "\t");
}
}
public static void main(String[] args) {
int[] array = new int[] {1, 3, 5};
fun(array);
}
}
// Output:
// 1 3 5
複製程式碼
陣列作為函式返回值的示例:
public class ArrayRefDemo2 {
/**
* 返回一個陣列
*/
private static int[] fun() {
return new int[] {1, 3, 5};
}
public static void main(String[] args) {
int[] array = fun();
System.out.println(Arrays.toString(array));
}
}
// Output:
// [1, 3, 5]
複製程式碼
泛型和陣列
通常,陣列和泛型不能很好地結合。你不能例項化具有引數化型別的陣列。
Peel<Banana>[] peels = new Pell<Banana>[10]; // 這行程式碼非法
複製程式碼
Java 中不允許直接建立泛型陣列。但是,可以通過建立一個型別擦除的陣列,然後轉型的方式來建立泛型陣列。
public class GenericArrayDemo<T> {
static class GenericArray<T> {
private T[] array;
public GenericArray(int num) {
array = (T[]) new Object[num];
}
public void put(int index, T item) {
array[index] = item;
}
public T get(int index) { return array[index]; }
public T[] array() { return array; }
}
public static void main(String[] args) {
GenericArray<Integer> genericArray = new GenericArray<Integer>(4);
genericArray.put(0, 0);
genericArray.put(1, 1);
Object[] array = genericArray.array();
System.out.println(Arrays.deepToString(array));
}
}
// Output:
// [0, 1, null, null]
複製程式碼
擴充套件閱讀:www.cnblogs.com/jiangzhaowe…
我認為,對於泛型陣列的理解,點到為止即可。實際上,真的需要儲存泛型,還是使用容器更合適。
多維陣列
多維陣列可以看成是陣列的陣列,比如二維陣列就是一個特殊的一維陣列,其每一個元素都是一個一維陣列。
Java 可以支援二維陣列、三維陣列、四維陣列、五維陣列。。。
但是,以正常人的理解能力,一般也就最多能理解三維陣列。所以,請不要做反人類的事,去定義過多維度的陣列。
多維陣列使用示例:
public class MultiArrayDemo {
public static void main(String[] args) {
Integer[][] a1 = { // 自動裝箱
{1, 2, 3,},
{4, 5, 6,},
};
Double[][][] a2 = { // 自動裝箱
{ {1.1, 2.2}, {3.3, 4.4} },
{ {5.5, 6.6}, {7.7, 8.8} },
{ {9.9, 1.2}, {2.3, 3.4} },
};
String[][] a3 = {
{"The", "Quick", "Sly", "Fox"},
{"Jumped", "Over"},
{"The", "Lazy", "Brown", "Dog", "and", "friend"},
};
System.out.println("a1: " + Arrays.deepToString(a1));
System.out.println("a2: " + Arrays.deepToString(a2));
System.out.println("a3: " + Arrays.deepToString(a3));
}
}
// Output:
// a1: [[1, 2, 3], [4, 5, 6]]
// a2: [[[1.1, 2.2], [3.3, 4.4]], [[5.5, 6.6], [7.7, 8.8]], [[9.9, 1.2], [2.3, 3.4]]]
// a3: [[The, Quick, Sly, Fox], [Jumped, Over], [The, Lazy, Brown, Dog, and, friend]]
複製程式碼
Arrays 類
Java 中,提供了一個很有用的陣列工具類:Arrays。
它提供的主要操作有:
sort
- 排序binarySearch
- 查詢equals
- 比較fill
- 填充asList
- 轉列表hash
- 雜湊toString
- 轉字串
擴充套件閱讀:juejin.im/post/5a6ade…