建立和初始化陣列

基本情況

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類,例如 ArrayListArrayList 將元素儲存在陣列中,並通過分配新陣列和複製舊陣列中的元素來支援調整大小

如果陣列是原始型別,即

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(見下圖)。

10 個元素的陣列

對陣列元素的訪問是在恆定時間內完成的。這意味著訪問陣列的第一個元素與訪問第二個元素,第三個元素等具有相同的成本(及時)。

Java 提供了幾種定義和初始化陣列的方法,包括文字建構函式符號。使用 new Type[length] 建構函式宣告陣列時,將使用以下預設值初始化每個元素:

  • 0原始數值型別byteshortintlongfloatdouble
  • char 型別的'\u0000'(空字元)。
  • falseboolean 型。
  • 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

來源 - 生活在 Ideone 上

建立和初始化引用型別陣列

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

住在 Ideone 上

除了上面顯示的 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
    }
}

相反,可以使用以下方法之一建立它們:(請注意,這些將生成未經檢查的警告)

  1. 通過建立 Object 陣列,並將其轉換為泛型型別:

    a = (T[]) new Object[5];
    

    這是最簡單的方法,但由於底層陣列仍然是 Object[] 型別,因此該方法不提供型別安全性。因此,這種建立陣列的方法最好只在泛型類中使用 - 不公開公開。

  2. 通過使用帶有類引數的 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" }

住在 Ideone 上

fill() 還可以為陣列的指定範圍的每個元素賦值:

Arrays.fill(array8, 1, 2, "aaa");  // Placing "aaa" from index 1 to 2.

住在 Ideone 上

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 }.

住在 Ideone 上

單獨宣告和初始化陣列

陣列元素的索引值必須是整數(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.

住在 Ideone 上