建立和初始化陣列
基本情況
int[] numbers1 = new int[3]; // Array for 3 int values, default value is 0
int[] numbers2 = { 1, 2, 3 }; // Array literal of 3 int values
int[] numbers3 = new int[] { 1, 2, 3 }; // Array of 3 int values initialized
int[][] numbers4 = { { 1, 2 }, { 3, 4, 5 } }; // Jagged array literal
int[][] numbers5 = new int[5][]; // Jagged array, one dimension 5 long
int[][] numbers6 = new int[5][4]; // Multidimensional array: 5x4
可以使用任何基元或引用型別建立陣列。
float[] boats = new float[5]; // Array of five 32-bit floating point numbers.
double[] header = new double[] { 4.56, 332.267, 7.0, 0.3367, 10.0 };
// Array of five 64-bit floating point numbers.
String[] theory = new String[] { "a", "b", "c" };
// Array of three strings (reference type).
Object[] dArt = new Object[] { new Object(), "We love Stack Overflow.", new Integer(3) };
// Array of three Objects (reference type).
對於最後一個示例,請注意陣列中允許宣告的陣列型別的子型別。
使用者定義型別的陣列也可以類似於基本型別構建
UserDefinedClass[] udType = new UserDefinedClass[5];
陣列,集合和流
Version => Java SE 1.2
// Parameters require objects, not primitives
// Auto-boxing happening for int 127 here
Integer[] initial = { 127, Integer.valueOf( 42 ) };
List<Integer> toList = Arrays.asList( initial ); // Fixed size!
// Note: Works with all collections
Integer[] fromCollection = toList.toArray( new Integer[toList.size()] );
//Java doesn't allow you to create an array of a parameterized type
List<String>[] list = new ArrayList<String>[2]; // Compilation error!
Version => Java SE 8
// Streams - JDK 8+
Stream<Integer> toStream = Arrays.stream( initial );
Integer[] fromStream = toStream.toArray( Integer[]::new );
介紹
一個陣列是一種資料結構,其保持原始值的固定數量或引用物件例項。
陣列中的每個項稱為元素,每個元素都由其數字索引訪問。建立陣列時建立陣列的長度:
int size = 42;
int[] array = new int[size];
**初始化時,陣列的大小在執行時是固定的。**初始化後無法更改。如果大小在執行時必須是可變的,則應該使用 Collection
類,例如 ArrayList
。ArrayList
將元素儲存在陣列中,並通過分配新陣列和複製舊陣列中的元素來支援調整大小 。
如果陣列是原始型別,即
int[] array1 = { 1,2,3 };
int[] array2 = new int[10];
值儲存在陣列本身中。在沒有初始化器的情況下(如上面的 array2
所示),分配給每個元素的預設值為 0
(零)。
如果陣列型別是物件引用,則如
SomeClassOrInterface[] array = new SomeClassOrInterface[10];
然後該陣列包含對 SomeClassOrInterface
型別的物件的引用。這些引用可以引用 SomeClassOrInterface
的例項或任何子類(用於類)或實現 SomeClassOrInterface
的類(用於介面) 。如果陣列宣告沒有初始值設定項,則會為每個元素分配預設值 null
。
因為所有陣列都是 int
-indexed,所以陣列的大小必須由 int
指定。陣列的大小不能指定為 long
:
long size = 23L;
int[] array = new int[size]; // Compile-time error:
// incompatible types: possible lossy conversion from
// long to int
陣列使用從零開始的索引系統,這意味著索引從 0
開始,到 length - 1
結束。
例如,下圖顯示大小為 10
的陣列。這裡,第一個元素位於索引 0
,最後一個元素位於索引 9
,而不是第一個元素位於索引 1
,而最後一個元素位於索引 10
(見下圖)。
對陣列元素的訪問是在恆定時間內完成的。這意味著訪問陣列的第一個元素與訪問第二個元素,第三個元素等具有相同的成本(及時)。
Java 提供了幾種定義和初始化陣列的方法,包括文字和建構函式符號。使用 new Type[length]
建構函式宣告陣列時,將使用以下預設值初始化每個元素:
0
為原始數值型別 :byte
,short
,int
,long
,float
和double
。char
型別的'\u0000'
(空字元)。false
為boolean
型。null
用於參考型別 。
建立和初始化基本型別陣列
int[] array1 = new int[] { 1, 2, 3 }; // Create an array with new operator and
// array initializer.
int[] array2 = { 1, 2, 3 }; // Shortcut syntax with array initializer.
int[] array3 = new int[3]; // Equivalent to { 0, 0, 0 }
int[] array4 = null; // The array itself is an object, so it
// can be set as null.
宣告陣列時,[]
將作為宣告開頭型別的一部分(在型別名稱之後)出現,或作為特定變數的宣告符的一部分(在變數名之後)或兩者出現:
int array5[]; /* equivalent to */ int[] array5;
int a, b[], c[][]; /* equivalent to */ int a; int[] b; int[][] c;
int[] a, b[]; /* equivalent to */ int[] a; int[][] b;
int a, []b, c[][]; /* Compilation Error, because [] is not part of the type at beginning
of the declaration, rather it is before 'b'. */
// The same rules apply when declaring a method that returns an array:
int foo()[] { ... } /* equivalent to */ int[] foo() { ... }
在下面的示例中,兩個宣告都是正確的,可以編譯和執行,沒有任何問題。但是,“ Java 編碼約定” 和“ Google Java 樣式指南” 都不鼓勵在變數名稱後帶括號的表單 - 括號標識陣列型別,並且應顯示型別名稱 。方法返回簽名也應該使用相同的方法。
float array[]; /* and */ int foo()[] { ... } /* are discouraged */
float[] array; /* and */ int[] foo() { ... } /* are encouraged */
不鼓勵的型別是為了適應轉換 C 使用者 ,他們熟悉 C 的語法,C 語言的變數名後面有括號。
在 Java 中,可以使用大小為 0
的陣列:
int[] array = new int[0]; // Compiles and runs fine.
int[] array2 = {}; // Equivalent syntax.
但是,由於它是一個空陣列,因此無法從中讀取任何元素或將其分配給它:
array[0] = 1; // Throws java.lang.ArrayIndexOutOfBoundsException.
int i = array2[0]; // Also throws ArrayIndexOutOfBoundsException.
這種空的陣列通常是作為返回值是有用的,使得呼叫程式碼只需要擔心與陣列處理,而不是潛在的 null
值,這可能導致一個 NullPointerException
。
陣列的長度必須是非負整數:
int[] array = new int[-1]; // Throws java.lang.NegativeArraySizeException
可以使用名為 length
的公共最終欄位確定陣列大小:
System.out.println(array.length); // Prints 0 in this case.
注意 :array.length
返回陣列的實際大小,而不是分配值的陣列元素的數量,這與 ArrayList.size()
不同,後者返回分配了值的陣列元素的數量。
建立和初始化多維陣列
建立多維陣列的最簡單方法如下:
int[][] a = new int[2][3];
它將建立兩個三長 int
陣列 - a[0]
和 a[1]
。這與矩形多維陣列的經典 C 風格初始化非常相似。
你可以同時建立和初始化:
int[][] a = { {1, 2}, {3, 4}, {5, 6} };
與 C 不同 ,只支援矩形多維陣列,內部陣列不需要具有相同的長度,甚至不需要定義:
int[][] a = { {1}, {2, 3}, null };
這裡,a[0]
是一個長度的 int
陣列,而 a[1]
是一個雙長度的 int
陣列,a[2]
是 null
。像這樣的陣列稱為鋸齒狀陣列或不規則陣列 ,也就是說,它們是陣列的陣列。Java 中的多維陣列實現為陣列陣列,即 array[i][j][k]
相當於 ((array[i])[j])[k]
。與 C#不同 ,Java 中不支援語法 array[i,j]
。
Java 中的多維陣列表示
https://i.stack.imgur.com/lbaMR.gif
建立和初始化引用型別陣列
String[] array6 = new String[] { "Laurel", "Hardy" }; // Create an array with new
// operator and array initializer.
String[] array7 = { "Laurel", "Hardy" }; // Shortcut syntax with array
// initializer.
String[] array8 = new String[3]; // { null, null, null }
String[] array9 = null; // null
除了上面顯示的 String
文字和基元之外,陣列初始化的快捷語法也適用於規範的 Object
型別:
Object[] array10 = { new Object(), new Object() };
因為陣列是協變的,所以可以將引用型別陣列初始化為子類的陣列,但是如果嘗試將元素設定為 String
以外的其他元素,則會丟擲 ArrayStoreException
:
Object[] array11 = new String[] { "foo", "bar", "baz" };
array11[1] = "qux"; // fine
array11[1] = new StringBuilder(); // throws ArrayStoreException
快捷語法不能用於此,因為快捷語法將具有隱式型別 Object[]
。
使用 String[] emptyArray = new String[0]
可以使用零元素初始化陣列。例如,當方法需要物件的執行時型別時,像 Collection
一樣使用長度為零的陣列來建立 Array
。
在原始型別和引用型別中,空陣列初始化(例如 String[] array8 = new String[3]
)將使用每種資料型別的預設值初始化陣列。
建立和初始化泛型型別陣列
在泛型類中,由於型別擦除, 無法像這樣初始化泛型型別的陣列 :
public class MyGenericClass<T> {
private T[] a;
public MyGenericClass() {
a = new T[5]; // Compile time error: generic array creation
}
}
相反,可以使用以下方法之一建立它們:(請注意,這些將生成未經檢查的警告)
-
通過建立
Object
陣列,並將其轉換為泛型型別:a = (T[]) new Object[5];
這是最簡單的方法,但由於底層陣列仍然是
Object[]
型別,因此該方法不提供型別安全性。因此,這種建立陣列的方法最好只在泛型類中使用 - 不公開公開。 -
通過使用帶有類引數的
Array.newInstance
:public MyGenericClass(Class<T> clazz) { a = (T[]) Array.newInstance(clazz, 5); }
這裡的
T
類必須顯式傳遞給建構函式。Array.newInstance
的返回型別總是Object
。但是,此方法更安全,因為新建立的陣列始終為T[]
型別,因此可以安全地外部化。
初始化後填充陣列
Version => Java SE 1.2
初始化後,Arrays.fill()
可用於填充具有相同值的陣列 :
Arrays.fill(array8, "abc"); // { "abc", "abc", "abc" }
fill()
還可以為陣列的指定範圍的每個元素賦值:
Arrays.fill(array8, 1, 2, "aaa"); // Placing "aaa" from index 1 to 2.
Version => Java SE 8
從 Java 版本 8 開始,方法 setAll
及其 Concurrent
等效 parallelSetAll
可用於將陣列的每個元素設定為生成的值。這些方法傳遞一個生成器函式,該函式接受一個索引並返回該位置的所需值。
以下示例建立一個整數陣列,並將其所有元素設定為各自的索引值:
int[] array = new int[5];
Arrays.setAll(array, i -> i); // The array becomes { 0, 1, 2, 3, 4 }.
單獨宣告和初始化陣列
陣列元素的索引值必須是整數(0,1,2,3,4,…)且小於陣列的長度(索引從零開始)。否則,將丟擲 ArrayIndexOutOfBoundsException :
int[] array9; // Array declaration - uninitialized
array9 = new int[3]; // Initialize array - { 0, 0, 0 }
array9[0] = 10; // Set index 0 value - { 10, 0, 0 }
array9[1] = 20; // Set index 1 value - { 10, 20, 0 }
array9[2] = 30; // Set index 2 value - { 10, 20, 30 }
不能使用陣列初始化快捷方式語法重新初始化陣列
由於陣列初始值設定項只能在欄位宣告或區域性變數宣告中指定,或者作為陣列建立表示式的一部分,因此無法通過帶有陣列初始值設定項的快捷語法重新初始化陣列 。
但是,可以建立一個新陣列並將其分配給用於引用舊陣列的變數。雖然這會導致該變數引用的陣列被重新初始化,但變數內容是一個全新的陣列。為此,new
運算子可以與陣列初始值設定項一起使用並分配給陣列變數:
// First initialization of array
int[] array = new int[] { 1, 2, 3 };
// Prints "1 2 3 ".
for (int i : array) {
System.out.print(i + " ");
}
// Re-initializes array to a new int[] array.
array = new int[] { 4, 5, 6 };
// Prints "4 5 6 ".
for (int i : array) {
System.out.print(i + " ");
}
array = { 1, 2, 3, 4 }; // Compile-time error! Can't re-initialize an array via shortcut
// syntax with array initializer.