Simple (One-dimensional) Arrays in Java

An array is a data structure. A data structure is an organized collection of data. In an array, data are arranged in a linear or sequential structure, with one element following another. When referencing elements in an array, we refer to the positions of the particular elements within the array. For example, if the array is named arr, then the elements are named arr[0], arr[1], arr[2], ... arr[n-1], where n gives the number of elements in the array. This naming also reflects the fact that the array’s data are contained in storage locations that are next to each other.

Array Indexes

In Java, as in C, C++, and some other programming languages, the first element of an array has index 0.

Figure showing an array named arr that contains 15 int elements.

Figure showing an array named arr that contains 15 int elements.

The figure above shows an array named arr that contains 15 int elements. The syntax for referring to elements of an array is:

arrayname [ index ]

Where arrayname is the name of the array any valid identifier will do and index is the position of the element within the array. As the figure shows, the first element in the array has index 0, the second has index 1, and so on.

A index is an integer within the square brackets that is used to identify an array element. An index must be either an integer value or an integer expression. To illustrate an example, suppose that j and k are integer variables equaling 5 and 7, respectively. Each of the following would then be a valid reference to elements of the array arr:

arr[4]     //Refers to 16
arr[j]     //Is arr[5] which refers to 20
arr[j + k] //Is arr[5+7] which is arr[12] which refers to 45
arr[k % j] //Is arr[7%5] which is arr[2] which refers to -1

These examples show that when an expression, such as j + k, is used as a index, it is evaluated (to 12 in this case) before the reference is made.

It is a syntax error to use a non-integer type as an array index. Each of the following expressions would be invalid:

arr[5.0]  // 5.0 is a float and can't be an array index
arr["5"]  // "5" is a string not an integer

Array Out of Bounds Error

For a given array, a valid array index must be in the range 0 ... N-1, where N is the number of elements in the array or it is considered out-of-bounds.

An out-of-bounds index creates a run-time error—that is, an error that occurs when the program is running—rather than a syntax error, which can be detected when the program is compiled. For the array arr, each of the following expressions contain out-of-bounds indexes:

arr[-1]  // Arrays cannot have negative subscripts
arr['5'] // Char '5' promoted to its Unicode value, 53
arr[15]  // The last element of arr has index 14
arr[j*k] // Since j*k equals 35

Each of these references would lead to an IndexOutOfBoundsException.

Declaring and Creating Arrays

For the most part, arrays in Java are treated as objects. Like objects, they are instantiated with the new operator and they have instance variables (for example, length). Like variables for objects, array variables are considered reference variables. When arrays are used as parameters, a reference to the array is passed rather than a copy of the entire array.

The primary difference between arrays and full-fledged objects is that arrays aren’t defined in terms of an Array class. Thus, arrays don’t fit into Java’s Object hierarchy. They don’t inherit any properties from Object and they cannot be subclassed.

You can think of an array as a container that contains a number of variables. As we’ve seen, the variables contained in an array object are not referenced by name but by their relative position in the array. The variables are called components. If an array object has N components, then we say that the array length is N. Each of the components of the array has the same type, which is called the array’s component type. An empty array is one that contains zero variables.

A one-dimensional array has components that are called the array’s elements. Their type is the array’s element type. An array’s elements may be of any type, including primitive and reference types. This means you can have arrays of int, char, boolean, String, Object, and so on.

When declaring a one-dimensional array, you have to indicate both the array’s element type and its length. Just as in declaring and creating other kinds of objects, creating an array object requires that we create both a name for the array and then the array itself. The following statements create the array shown in the figure above:

int arr[];          // Declare a name for the array
arr = new int[15];  // Create the array itself

These two steps can be combined into a single statement as follows:

int arr[] = new int[15];

In this example, the array’s element type is int and its length is 15, which is fixed and cannot be changed. This means that the array contains 15 variables of type int, which will be referred to as arr[0], arr[1],...arr[14].

Array Allocation

Creating the array in the figure near the top means allocating 15 storage locations that can store integers. Note that one difference between declaring an array and declaring some other kind of object is that square brackets [] are used to declare an array type. The brackets can be attached either to the array’s name or to its type, as in the following examples:

int arr[];     // The brackets may follow the array's name
int[] arr;     // The brackets may follow the array's type

The following example creates an array of five Strings and then uses a for loop to assign the strings “hello1”, “hello2”, “hello3”, “hello4”, and “hello5” to the five array locations:

String strarr[];          // Declare a name for the array
strarr = new String[5];   // Create the array itself

// Assign strings to the array
for (int k = 0; k < strarr.length; k++) {     // For each element
  strarr[k] = new String("hello" + (k + 1));  // Assign a string
}

Note that the expression k < strarr.length specifies the loop bound. Every array has a length instance variable, which refers to the number of elements contained in the array. As we mentioned, arrays, like Strings, are zero indexed, so the last element of the array is always given by its length-1. However, length is an instance variable for arrays, whereas length() is an instance method for Strings. Therefore, it would be a syntax error in this example to refer to strarr.length().

In the example, we first use the new operator to create strarr, an array of type String of length five. We then use a String constructor to create the five Strings that are stored in the array. It is important to realize that creating an array to store five Objects (as opposed to five primitive data elements) does not also create the Objects themselves that will be stored in the array.

Creating an array of five Strings involves six objects, because the array itself is a separate object. In (a), the array variable is declared. In (b), the array is instantiated, creating an array of five null references. In (c), the five Strings are created and assigned to the array.

Creating an array of five Strings involves six objects, because the array itself is a separate object. In (a), the array variable is declared. In (b), the array is instantiated, creating an array of five null references. In (c), the five Strings are created and assigned to the array.

When an array of objects is created, the array’s elements are references to those objects. Their initial values, like all reference variables, are null. So to create and initialize the array strarr, we need to create 6 objects: the array itself, which will contain five Strings, and then the five Strings that are stored in strarr.

One more example will help underscore this point. The following statements create four new Objects, an array to store three Students plus the three Students themselves:

Student school[] = new Student[3];   // A 3 Student array
school[0] = new Student("Socrates"); // The first Student
school[1] = new Student("Plato");    // The second Student
school[2] = new Student("Aristotle");// The third Student

The first statement creates an array named school to store three s, and the next three statements create the individual Students and assign them to the array see figure below. Thus, creating the array and initializing its elements require 4 new statements.

Arrays of objects store references to the objects, not the objects themselves

Arrays of objects store references to the objects, not the objects themselves

The following sequence of statements would lead to a null pointer exception (NPE) because the array’s elements have not been instantiated:

Student students[] = new Student[3]; // A 3 Student array
System.out.println(students[0].getName());

In this case, students[0] is a null reference, thus results in the NPE exception.

Now that we’ve assigned the three Students to the array, we can refer to them by means of subscripted references. A reference to the named “Socrates” is now school[0], and a reference to the named “Plato” is school[1]. In other words, to refer to the three individual students we must refer to their locations within school. Of course, we can also use variables, such as loop counters, to refer to a Student’s location within school. The following for loop invokes each Student’s getState() method to print out its current state:

for (int k = 0; k < school.length; k++) {
  System.out.println(school[k].getState());
}

What if the three Students already existed before the array was created? In that case, we could just assign their references to the array elements, as in the following example:

Student student1 = new Student("Socrates"); 
Student student2 = new Student("Plato");
Student student3 = new Student("Aristotle");
Student school = new Student[3]; // A 3 Student array (Codeahoy.com)
school[0] = student1;
school[1] = student2;
school[2] = student3;

In this case, each of the three Student objects can be referenced by two different references: its variable identifier (such as student1) and its array location (such as school[0]). For arrays of objects, Java stores just the reference to the object in the array itself, rather than the entire object. This conserves memory, since references require only 4 bytes each whereas each object may require hundreds of bytes.

When an array of N elements is created, the compiler allocates storage for N variables of the element’s type. In the case of arr that we discussed earlier, the compiler would allocate storage for 15 ints. 60 contiguous bytes of storage, because each int requires 4 bytes (32 bits) of storage. If we declare an array of 20 doubles:

double arr[] = new double[20];

the compiler will allocate 160 bytes of storage—20 variables of 8 bytes (64 bits) each. In the case of the examples and String examples, because these are objects (not primitive types), the compiler will allocate space for N addresses, where N is the length of the array and where each address requires 4 bytes.

Initializing Arrays

Array elements are automatically initialized to default values that depend on the element type: Boolean elements are initialized to false, and integer and real types are initialized to 0. Reference types, arrays of objects, are initialized to null.

Arrays can also be assigned initial values when they are created, although this is feasible only for relatively small arrays. An array initializer is written as a list of expressions separated by commas and enclosed by braces. For example, we can declare and initialize the array shown in figure at the top with the following statement:

int arr[] = {-2,8,-1,-3,16,20,25,16,16,8,18,19,45,21,-2};

Similarly, to create and initialize an array of Strings, we can use the following statement:

String strings[] = {"hello", "world", "goodbye", "love"};

This example creates and stores four Strings in the array. Subsequently, to refer to “hello”, we would use the reference strings[0], and to refer to “love”, we would use the reference strings[3]. Note in these examples that when an array declaration contains an initializer, it is not necessary to use new and it is not necessary to specify the number of elements in the array. The number of elements is inferred from the number of values in the initializer list.

Assigning and Using Array Values

Array elements can be used in the same way as other variables. The only difference, of course, is that references to the elements are indexed. For example, the following assignment statements assign values to the elements of two arrays, named arr and strings:

arr[0] = 5;
arr[5] = 10;
arr[2] = 3;
strings[0] = "who";
strings[1] = "what";
strings[2] = strings[3] = "where";

The following loop assigns the first 15 squares 1, 4, 9... to the array arr:

for (int k = 0; k < arr.length; k++) {
  arr[k] = (k+1) * (k+1);
}

The following loop prints the values of the array arr:

for (int k = 0; k < arr.length; k++) {
  System.out.println(arr[k]);
}

Licenses and Attributions


Speak Your Mind