An array is a data structure that defines an indexed collection of a fixed number of homogeneous data elements. This means that all elements in the array have the same data type. A position in the array is indicated by a non-negative integer value called the index. An element at a given position in the array is accessed using the index. The size of an array is fixed and cannot increase to accommodate more elements.
In Java, arrays are objects. Arrays can be of primitive data types or reference types. In the former case, all elements in the array are of a specific primitive data type. In the latter case, all elements are references of a specific reference type. References in the array can then denote objects of this reference type or its subtypes. Each array object has a final field called length, which specifies the array size, that is, the number of elements the array can accommodate. The first element is always at index 0 and the last element at index n-1, where n is the value of the length field in the array.
Simple arrays are one-dimensional arrays, that is, a simple sequence of values. Since arrays can store object references, the objects referenced can also be array objects. This allows implementation of array of arrays.
Passing array references as parameters is discussed in Section 3.20. Type conversions for array references on assignment and method invocation are discussed in Section 6.6.
An array variable declaration has either the following syntax:
<element type>[] <array name>;
or
<element type> <array name>[];
where <element type> can be a primitive data type or a reference type. The array variable <array name> has the type <element type>[]. Note that the array size is not specified. This means that the array variable <array name> can be assigned an array of any length, as long as its elements have <element type>.
It is important to understand that the declaration does not actually create an array. It only declares a reference that can denote an array object.
int anIntArray[], oneInteger; Pizza[] mediumPizzas, largePizzas;
These two declarations declare anIntArray and mediumPizzas to be reference variables that can denote arrays of int values and arrays of Pizza objects, respectively. The variable largePizzas can denote an array of pizzas, but the variable oneInteger cannot denote an array of int values?it is simply an int variable.
When the [] notation follows the type, all variables in the declaration are arrays. Otherwise the [] notation must follow each individual array name in the declaration.
An array variable that is declared as a member of a class, but is not initialized to denote an array, will be initialized to the default reference value null. This default initialization does not apply to local reference variables and, therefore, does not apply to local array variables either (see Section 2.4, p. 33). This should not be confused with initialization of the elements of an array during array construction.
An array can be constructed for a specific number of elements of the element type, using the new operator. The resulting array reference can be assigned to an array variable of the corresponding type.
<array name> = new <element type> [<array size>];
The minimum value of <array size> is 0 (i.e., arrays with zero elements can be constructed in Java). If the array size is negative, a NegativeArraySizeException is thrown.
Given the following array declarations:
int anIntArray[], oneInteger; Pizza[] mediumPizzas, largePizzas;
the arrays can be constructed as follows:
anIntArray = new int[10]; // array for 10 integers mediumPizzas = new Pizza[5]; // array of 5 pizzas largePizzas = new Pizza[3]; // array of 3 pizzas
The array declaration and construction can be combined.
<element type1>[] <array name> = new <element type2>[<array size>];
However, here array type <element type2>[] must be assignable to array type <element type1>[] (see Section 6.6, p. 260). When the array is constructed, all its elements are initialized to the default value for <element type2>. This is true for both member and local arrays when they are constructed.
In all the examples below, the code constructs the array and the array elements are implicitly initialized to their default value. For example, the element at index 2 in array anIntArray gets the value 0, and the element at index 3 in array mediumPizzas gets the value null when the arrays are constructed.
int[] anIntArray = new int[10]; // Default element value: 0. Pizza[] mediumPizzas = new Pizza[5]; // Default element value: null. // Pizza class extends Object class Object objArray = new Pizza[3]; // Default element value: null. // Pizza class implements Eatable interface Eatable[] eatables = new Pizza[2]; // Default element value: null.
The value of the field length in each array is set to the number of elements specified during the construction of the array; for example, medium Pizzas.length has the value 5.
Once an array has been constructed, its elements can also be explicitly initialized individually; for example, in a loop. Examples in the rest of this section make heavy use of a loop to traverse through the elements of an array for various purposes.
Java provides the means of declaring, constructing, and explicitly initializing an array in one declaration statement:
<element type>[] <array name> = { <array initialize list> };
This form of initialization applies to member as well as local arrays. The <array initialize list> is a comma-separated list of zero or more expressions. Such an array initialization block results in the construction and initialization of the array.
int[] anIntArray = {1, 3, 49, 2, 6, 7, 15, 2, 1, 5};
The array anIntArray is declared as an array of ints. It is constructed to hold 10 elements (equal to the length of the list of expressions in the block), where the first element is initialized to the value of the first expression (1), the second element to the value of the second expression (3), and so on.
// Pizza class extends Object class Object[] objArray = { new Pizza(), new Pizza(), null };
The array objArray is declared as an array of the Object class, constructed to hold three elements. The initialization code sets the first two elements of the array to refer to two Pizza objects, while the last element is initialized to the null reference. Note that the number of objects created in the above declaration statement is actually three: the array object with three references and the two Pizza objects.
The expressions in the <array initialize list> are evaluated from left to right, and the array name obviously cannot occur in any of the expressions in the list. In the examples above, the <array initialize list> is terminated by the right curly bracket, }, of the block. The list can also be legally terminated by a comma. The following array has length two, not three:
Topping[] pizzaToppings = { new Topping("cheese"), new Topping("tomato"), };
The declaration statement at (1) in the following code defines an array of four String objects, while the declaration statement at (2) should make it clear that a String object is not the same as an array of char.
// Array with 4 String objects String[] pets = {"crocodiles", "elephants", "crocophants", "elediles"}; // (1) // Array of 3 characters char[] charArray = {'a', 'h', 'a'}; // (2) Not the same as "aha".
The whole array is referenced by the array name, but individual array elements are accessed by specifying an index with the [] operator. The array element access expression has the following syntax:
<array name> [<index expression>]
Each individual element is treated as a simple variable of the element type. The index is specified by the <index expression>, which can be any expression that evaluates to an non-negative int value. Since the lower bound of an array is always 0, the upper bound is one less than the array size, that is, (<array name>.length-1). The ith element in the array has index (i-1). At runtime, the index value is automatically checked to ensure that it is within the array index bounds. If the index value is less than 0 or greater than or equal to <array name>.length in an array element access expression, an ArrayIndexOutOfBoundsException is thrown. A program can either check the index explicitly or catch the exception (see Section 5.5, p. 181), but an illegal index is typically an indication of a program bug.
In the array element access expression, the <array name> can, in fact, be any expression that returns a reference to an array. For example, the following expression accesses the element with the index 1 in the character array returned by a call to the toCharArray() method of the String class: "AHA".toCharArray()[1].
The array operator [] is used to declare array types (Topping[]), specify array size (new Toppings[3]), and to access array elements (toppings[1]). This operator is not used when the array reference is manipulated, for example in an array reference assignment (see Section 6.6, p. 260) or when the array reference is passed as an actual parameter in a method call (see Section 3.20, p. 91).
Example 4.1 shows traversal of arrays. The loop at (3) initializes the local array trialArray declared at (2) five times with pseudo-random numbers (from 0.0 to 100.0), by calling the method randomize() at (5). The minimum value in the array is found by calling the method findMinimum() at (6), and is stored in the array storeMinimum declared at (1). The loop at (4) prints the minimum values from the trials. The start value of the loop variable is initially set to 0. The loop condition tests whether the loop variable is less than the length of the array; this guarantees that the index will not go out of bounds.
class Trials { public static void main(String[] args) { // Declare and construct the local arrays double[] storeMinimum = new double[5]; // (1) double[] trialArray = new double[15]; // (2) for (int i = 0; i < storeMinimum.length; ++i) { // (3) // Initialize the array randomize(trialArray); // Find and store the minimum value storeMinimum[i] = findMinimum(trialArray); } // Print the minimum values (4) for (int i = 0; i < storeMinimum.length; ++i) System.out.println(storeMinimum[i]); } public static void randomize(double[] valArray) { // (5) for (int i = 0; i < valArray.length; ++i) valArray[i] = Math.random() * 100.0; } public static double findMinimum(double[] valArray) { // (6) // Assume the array has at least one element. double minValue = valArray[0]; for (int i = 1; i < valArray.length; ++i) minValue = Math.min(minValue, valArray[i]); return minValue; } }
Possible output from the program:
6.756931310985048 5.364063199341363 8.359410202984296 8.858272848258109 9.759950059619849
As shown earlier in this section, the following declaration statement
<element type1>[] <array name> = new <element type2>[<array size>]; // (1)
int[] intArray = new int[5];
can be used to construct arrays using an array creation expression. The size of the array is specified in the array creation expression, which creates the array and initializes the array elements to their default values. On the other hand, the following declaration statement
<element type>[] <array name> = { <array initialize list> }; // (2)
int[] intArray = {3, 5, 2, 8, 6};
both creates the array and initializes the array elements to specific values given in the array initializer block. However, the array initialization block is not an expression.
Java has another array creation expression, called anonymous array, which allows the concept of the array creation expression from (1) and the array initializer block from (2) to be combined, to create and initialize an array object:
new <element type>[] { <array initialize list> }
new int[] {3, 5, 2, 8, 6}
The construct has enough information to create a nameless array of a specific type. Neither the name of the array nor the size of the array is specified. The construct returns an array reference that can be assigned and passed as parameter. In particular, the following two examples of declaration statements are equivalent.
int[] intArray = {3, 5, 2, 8, 6}; // (1) int[] intArray = new int[] {3, 5, 2, 8, 6}; // (2)
In (1), an array initializer block is used to create and initialize the elements. In (2), an anonymous array expression is used. It is tempting to use the array initialization block as an expression; for example, in an assignment statement as a short cut for assigning values to array elements in one go. However, this is illegal?instead, an anonymous array expression should be used.
int[] daysInMonth; daysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // Not ok. daysInMonth = new int[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // ok.
The concept of anonymous arrays is similar to that of anonymous classes (see Section 7.5, p. 308): they both combine the definition and instantiation of classes into one process.
In Example 4.2, an anonymous array is constructed at (1) and passed as parameter to the static method findMinimum() defined at (2). Note that no array name or array size is specified for the anonymous array.
class AnonArray { public static void main(String[] args) { System.out.println("Minimum value: " + findMinimum(new int[] {3, 5, 2, 8, 6})); // (1) } public static int findMinimum(int[] dataSeq) { // (2) // Assume the array has at least one element. int min = dataSeq[0]; for (int index = 1; index < dataSeq.length; ++index) if (dataSeq[index] < min) min = dataSeq[index]; return min; } }
Output from the program:
Minimum value: 2
Since an array element can be an object reference and arrays are objects, array elements can themselves reference other arrays. In Java, an array of arrays can be defined as follows:
<element type>[][]...[] <array name>;
or
<element type> <array name>[][]...[];
In fact, the sequence of square bracket pairs, [], indicating the number of dimensions, can be distributed as a postfix to both the element type and the array name. Arrays of arrays are also sometimes called multidimensional arrays.
The following declarations are all equivalent:
int[][] mXnArray; // 2-dimensional array int[] mXnArray[]; // 2-dimensional array int mXnArray[][]; // 2-dimensional array
It is customary to combine the declaration with the construction of the multidimensional array.
int[][] mXnArray = new int[4][5]; // 4 x 5 matrix of ints
The previous declaration constructs an array mXnArray of four elements, where each element is an array (row) of 5 int values. The concept of rows and columns is often used to describe the dimensions of a 2-dimensional array, which is often called a matrix. However, such an interpretation is not dictated by the Java language.
Each row in the previous matrix is denoted by mXnArray[i], where 0 i < 4. Each element in the ith row, mXnArray[i], is accessed by mXnArray[i][j], where 0 j < 5. The number of rows is given by mXnArray.length, in this case 4, and the number of values in the ith row is given by mXnArray[i].length, in this case 5 for all the rows, where 0 i < 4.
Multidimensional arrays can also be constructed and explicitly initialized using array initializer blocks discussed for simple arrays. Note that each row is an array which uses an array initializer block to specify its values:
double[][] identityMatrix = { {1.0, 0.0, 0.0, 0.0 }, // 1. row {0.0, 1.0, 0.0, 0.0 }, // 2. row {0.0, 0.0, 1.0, 0.0 }, // 3. row {0.0, 0.0, 0.0, 1.0 } // 4. row }; // 4 x 4 Floating-point matrix
Arrays in a multidimensional array need not have the same length. The array of arrays pizzaGalore in the code below will have five rows, the first four rows have different lengths but the fifth row is left unconstructed.
Pizza[][] pizzaGalore = { { new Pizza(), null, new Pizza() }, // 1. row is an array of 3 elements. { null, new Pizza()}, // 2. row is an array of 2 elements. new Pizza[1], // 3. row is an array of 1 element. {}, // 4. row is an array of 0 elements. null // 5. row is not constructed. };
When constructing multidimensional arrays with the new operator, the length of the deeply nested arrays may be omitted. In this case, these arrays are left unconstructed. For example an array of arrays to represent a room on a floor in a hotel on a street in a city can have the type HotelRoom[][][][]. From left to right, the square brackets represent indices for street, hotel, floor, and room, respectively. This 4-dimensional array of arrays can be constructed piecemeal, starting with the leftmost dimension and proceeding to the rightmost.
HotelRoom[][][][] rooms = new HotelRoom[10][5][][]; // Just streets and hotels.
The above declaration constructs the array of arrays rooms partially with ten streets, where each street has five hotels. Floors and rooms can be added to a particular hotel on a particular street:
rooms[0][0] = new HotelRoom[3][]; // 3 floors in 1st. hotel on 1st. street. rooms[0][0][0] = new HotelRoom[8]; // 8 rooms on 1st. floor in this hotel. rooms[0][0][0][0] = new HotelRoom(); // Initialize 1st. room on this floor.
The code below constructs an array of arrays matrix, where the first row has one element, the second row has two elements, and the third row has three elements. Note that the outer array is constructed first. The second dimension is constructed in a loop that constructs the array in each row. The elements in the multidimensional array will be implicitly initialized to the default double value (0.0D). In Figure 4.1, the array of arrays matrix is depicted after the elements have been explicitly initialized.
double[][] matrix = new double[3][]; // No. of rows. for (int i = 0; i < matrix.length; ++i) matrix[i] = new double[i + 1]; // Construct a row.
Two other ways of initializing such an array of arrays, the first one using array initializer blocks and the second one using an anonymous array of arrays are shown as follows:
double[][] matrix2 = { {0.0}, // 1. row {0.0, 0.0}, // 2. row {0.0, 0.0, 0.0} // 3. row } double[][] matrix3 = new double[][] { {0.0}, // 1. row {0.0, 0.0}, // 2. row {0.0, 0.0, 0.0} // 3. row }
The type of variable matrix is double[][] (i.e., a two-dimensional array of double values). The type of variable matrix[i] (where 0 i< matrix.length) is double[] (i.e., a one-dimensional array of double values). The type of variable matrix[i][j] (where 0 i< matrix.length and 0 j< matrix[i].length) is double (i.e., a simple variable of type double).
Nested loops are a natural match for manipulating multidimensional arrays. In Example 4.3, a rectangular 4 x 3 int matrix is declared and constructed at (1). The program finds the minimum value in the matrix. The outer loop at (2) traverses the rows (mXnArray[i], 0 i< mXnArray.length), and the inner loop at (3) traverses the elements in each row in turn (mXnArray[i][j], 0 j< mXnArray[i].length). The outer loop is executed mXnArray.length times, or 4 times, and the inner loop is executed (mXnArray.length) x (mXnArray[i].length), or 12 times, since all rows have the same length, 3.
class MultiArrays { public static void main(String[] args) { // Declare and construct the M X N matrix. int[][] mXnArray = { // (1) {16, 7, 12}, // 1. row { 9, 20, 18}, // 2. row {14, 11, 5}, // 3. row { 8, 5, 10} // 4. row }; // 4 x 3 int matrix // Find the minimum value in a M X N matrix int min = mXnArray[0][0]; for (int i = 0; i < mXnArray.length; ++i) // (2) // Find min in mXnArray[i], i.e. in the row given by index i. for (int j = 0; j < mXnArray[i].length; ++j) // (3) min = Math.min(min, mXnArray[i][j]); System.out.println("Minimum value: " + min); } }
Output from the program:
Minimum value: 5