Arrays
- Understand how arrays are implemented in Java
- Declare, instantiate, populate, and use arrays of primitives
- Use arrays of objects
- Use multi-dimensional arrays
Arrays
Defining and Declaring Arrays
An array stores a group of data items all of the same type
An array is an object
- an array variable does not actually store the array - it is a reference variable that points to an array object
- declaring the array variable does not create an array object instance; it merely creates the reference variable - the array object must be instantiated separately
- once instantiated, the array object contains a block of memory locations for the individual elements
- if the individual elements are not explicitly initialized, they will be set to zero
- arrays can be created with a size that is determined dynamically (but once created, the size is fixed)
Declare an array variable by specifying the type of data to be stored, followed by square brackets []
dataType[] variableName;
- you can read the [] as the word "array"
To declare a variable for an array of integers:
int[] nums;
- which you can read as "int array nums"
To declare a variable for an array of String objects:
String[] names;
- which you can read as "String array names" - the array holds String references
You may also put the brackets after the variable name (as in C/C++), but that is less clearly related to how Java actually works
int nums[]; // not recommended, but legal
Instantiating Arrays
Instantiate an array object using new, the data type, and an array size in square brackets
int[] nums; nums = new int[10];
- the second line constructs a new array object with 10 integer elements, all initialized to 0, and stores the reference into nums
int[] moreNums; int size = 7; moreNums = new int[size];
- you can declare and instantiate all at once
String[] names = new String[3];
- the elements of the array, String references, are initialized to null
As objects, arrays also have a useful property: length
- in the above example, names.length would be 3
- the property is fixed (i.e., it is read-only)
You can reassign a new array to an existing variable
int[] nums; nums = new int[10]; nums = new int[20];
- the original ten-element array is no longer referenced by nums, since it now points to the new, larger array
Initializing Arrays
An array can be initialized when it is created
- the notation looks like this:
String[] names = { "Joe", "Jane", "Herkimer" };
or
String[] names = new String[] {"Joe", "Jane", "Herkimer" };
- this automatically creates an array of length 3, because there were 3 items supplied
int[] nums = new int[] { 2, 4, 6, 8, 10, 12 };
- this array will have a length of 6
If a new array is being assigned to an existing variable, you cannot use the shorter variant, you must use the new keyword and the data type:
String[] names;
names = new String[] {"Joe", "Jane", "Herkimer" };
For arrays of other types of objects:
Book[] titles;
titles = new Book[] {
new Book(5011, "Fishing Explained"),
new Book(1234, "Help is on the Way")
};
Working With Arrays
Array elements are accessed through the array reference, by their array index
- the index is the element number, placed within brackets
- elements are numbered from 0 to one less than the specified size
String[] names = new String[3];
- the valid elements are 0, 1, and 2, as in
names[0] = "Sam"; names[1] = "Sue"; names[2] = "Mary";
- you could access array elements in a for loop with:
for (int i = 0; i < 3; i++) System.out.println(names[i]);
- or, better programming practice would be to use the length property:
for (int i = 0; i < names.length; i++) System.out.println(names[i]);
The compiler does no checking to ensure that you stay within the bounds of the array
- but the JVM does check at runtime - if you try to exceed the bounds of the array, an exception will occur
Note that a zero-length array is valid:
Book[] titles = new Book[] { };
Book[] moreTitles = new Book[0];
- you might create a zero-length array as the return value from a method typed as returning an array, when there are no items to return (as opposed to returning null)
Code Sample: Java-Arrays/Demos/Arrays1.java
import java.util.*;
public class Arrays1 {
public static void main(String[] args) {
Random r = new Random();
int[] nums = new int[10];
for (int i = 0; i < nums.length; i++) {
nums[i] = r.nextInt(100);
}
System.out.println("Element 7 is: " + nums[7]);
String[] names = new String[3];
names[0] = "Joe";
names[1] = "Jane";
names[2] = "Herkimer";
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]);
}
//this line should throw an exception
System.out.println(names[6]);
}
}
Array Variables
The array as a whole can be referenced by the array name without the brackets, for example, as a parameter to or return value from a function
Code Sample: Java-Arrays/Demos/Arrays2.java
public class Arrays2 {
public static void main(String[] args) {
String[] names = new String[3];
names[0] = "Joe";
names[1] = "Jane";
names[2] = "Herkimer";
printArray(names);
}
public static void printArray(String[] data) {
for (int i = 0; i < data.length; i++) {
System.out.println(data[i].toUpperCase());
}
}
}
The array names is passed to printArray, where it is received as data.
Note also the syntax to access a method directly for an array element: data[i].toUpperCase()
Since an array reference is a variable, it can be made to refer to a different array at some point in time
String[] names = new String[3]; names[0] = "Joe"; names[1] = "Jane"; names[2] = "Herkimer"; printArray(names); names = new String[2]; names[0] = "Rudolf"; names[1] = "Ingrid"; printArray(names);
Copying Arrays
You can use System.arraycopy to copy an array into another
- you might do this to expand an array by creating a larger one and copying the contents of the smaller one into it (but any references to the original array will need to be changed to point to the new array)
- the declaration is:
public static void arraycopy( Object src, int srcPos, Object dest, int destPos, int length)
Code Sample: Java-Arrays/Demos/CopyArray.java
// puts two copies of a small array into a larger one
public class CopyArray {
public static void main(String[] args) {
int nums[] = { 1, 2, 3, 4, 5 };
int biggerNums[] = new int[10];
System.arraycopy(nums, 0, biggerNums, 0, nums.length);
System.arraycopy(nums, 0, biggerNums,
nums.length, nums.length);
for (int i = 0; i < biggerNums.length; i++)
System.out.println(biggerNums[i]);
}
}
- The first arraycopy line copys from nums into the first half of biggerNums. The number of items copied is determined by nums.length
System.arraycopy(nums, 0, biggerNums, 0, nums.length);- The second arraycopy line again copys from nums, but now into the second half of biggerNums. The starting location for the "paste" is nums.length, since that is where we left off the first time. And the number of items copied is again determined by nums.length
System.arraycopy(nums, 5, biggerNums, nums.length, nums.length);
Exercise: Using the args Array
- Note that there has been an array declaration in all of our examples
thus far; the array of strings passed to main: args
- these are the additional words on the command line
- Copy Hello.java to HelloArgs.java, and modify that to loop through args to print each element (remember to rename the class in the declaration line)
- Then run the program with something like java HelloArgs From Me and see what happens
Exercise: Game-Arrays01: A Guessing Game with Random Messages
- Modify your guessing game program to hold an array of several different String messages, all of which have some form of message for "Correct"
- Generate a random number in the range from 0 to the size of the array
- Use this value to select one message to print when they guess correctly
- Continue this approach for "Too Low" and "Too High"
Arrays of Objects
If an array contains objects, those objects' properties and methods may be accessed
- the notation uses the array variable name, the index in brackets, a dot, and the property or method
Code Sample: Java-Arrays/Demos/Arrays2.java
public class Arrays2 {
public static void main(String[] args) {
String[] names = new String[3];
names[0] = "Joe";
names[1] = "Jane";
names[2] = "Herkimer";
printArray(names);
}
public static void printArray(String[] data) {
for (int i = 0; i < data.length; i++) {
System.out.println(data[i].toUpperCase());
}
}
}
Exercise: Payroll-Arrays01: An Array of employees
- Modify the payroll program to use an array of Employee objects with a size of 3 or more (later we will come up with a more flexible solution that allows for the number of employees to change dynamically)
- Use a for loop to populate and display the data
- After the loop is complete, ask the user to enter a last name
- Loop through the array to find the element with the matching last name and display it
Enhanced for Loops - the For-Each Loop
Java 5 introduced the for-each loop, which loops through a collection of values without using an index. Instead, the loop variable repesents each individual value.
The syntax uses a loop variable and a collection of values, separated by a colon character (which can be read as the word "from").
- the collection of values can be any array or an instance of one of the Java Collections classes (to be discussed later)
- note that the looping variable must be declared in the parentheses that create the loop - you cannot use a preexisting variable as the loop variable
- the looping variable will represent each item from the collection or array in turn
for (dataType loopVariable : collectionOfSameType) code using loopVariable;
Multi-Dimensional Arrays
Arrays may have more than one dimension, for such things as:
- a graphic image that is x pixels across and y pixels vertically
- weather information modeled in a 3-dimensional space, with measurements for these axes: North/South, East/West, and altitude
Declare a multidimensional array as:
datatype[][] ... [] arrayName;
Arrays are objects, and, like other objects, declaring a variable does not instantiate the array - that must be done separately. To instantiate a multidimensional array:
arrayName = new datatype[size1][size2] ... [sizeN];
- the most significant dimension is listed first; the least significant dimension listed last
int[][] picture = new int[480][640];
- could be used to declare an array to store an image that is 640 pixels across and 480 pixels down - in a graphic the image data is stored sequentially across each row; each row is a 640 pixel block; there are 480 of these blocks in our image
int[][][] picture = new int[3][480][640];
- this might be used for an image where the data is stored in three layers, each of which is an entire 480 by 640 array.
Multidimensional Arrays in Memory
Recall that a matched pair of brackets after a data type means an array of that type
- and an array is a type of data
- so a two dimensional array written as this:
int[][] nums;
- could be thought of as an array of integer arrays, as if it were written as (note that this is not legal syntax):
(int[])[] nums;
In Java, a two-dimensional array is actually a single array of array reference variables, each of which points to a single dimensional array
To extend the example above:
int[][] nums = new int[3][6];
- this is an array of 3 elements, each of which is an array of 6 int elements
Note that it is possible to replace any of the one-dimensional elements with a different one, or that the second-dimension arrays each have a different length - the following line would replace one of the arrays with another of a different length
nums[1] = new int[4];
Example - Printing a Picture
This example uses a two-dimensional array preloaded with text characters that make up a picture
- there is a loop that processes each row (the first, or most significant, dimension of the array, each element of which is an array of characters)
- within that loop, another loop prints each character without ending the line
- then, when the inner loop is done, a newline is printed
Code Sample: Java-Arrays/Demos/ArrayPicture.java
public class ArrayPicture {
public static void main(String[] args) {
char[][] imgData =
new char[][] {
{ ' ',' ',' ',' ',' ',' ',' ' },
{ ' ',' ',' ','0',' ',' ',' ' },
{ ' ',' ',' ','|',' ',' ',' ' },
{ ' ','0','-','+','-','0',' ' },
{ ' ',' ',' ','|',' ',' ',' ' },
{ ' ',' ',' ','0',' ',' ',' ' },
{ ' ',' ',' ',' ',' ',' ',' ' }
};
for (int row = 0; row < imgData.length ; row++ ) {
for (int col = 0; col < imgData[row].length; col++ ) {
System.out.print(imgData[row][col]);
}
System.out.println();
}
}
}
Because multi-dimensional arrays are implemented as arrays of array references, it is possible to partially instantiate an array:
int[][] nums = new int[3][];
This creates nums as a two-dimensional array (better viewed in this case as an array of array references), and creates an array holding three null references to integer arrays
Exercise: Payroll-Arrays02: An Array for Dependents (optional)
We would like to keep track of our employees' dependents; the plan is to have the Employee class contain an array of objects, each of which represents one dependent
The class representing a dependent should contain a reference to the employee that it belongs to, in case we need to look up any employee-related information from a dependent reference
- Create a new class (in the employees package) called Dependent, with String properties for first and last names, and property called dependentOf, whose type is Employee
- It should have a constructor that accepts values for all three properties - give the constructor package access instead of public
- It should have set and get methods for the name properties, and only a get method for the employee they are a dependent of
- Add a property called dependents to Employee that
is an array of Dependent objects, and instantiate a five-element
array
- while this isn't the best practice, there isn't a much better solution, since the fundamental problem is that an array isn't really a good idea for a set of items with no fixed size - a collection class would be better
- it would, however, be an improvement to have a method like createDependentArray(int size) that could at least provide each employee with an individually sized array (which still couldn't be expanded)
- feel free to implement this ehnancement if you have time
- It is generally considerered a risky practice to create get and set methods for an array property - it exposes too much of the inner workings of the class to outside code (since it would enable wholesale replacement of the array or of the array's contents). Instead, we can control the array through properties and methods in the Employee class. To start, add an int numDependents property to Employee.
- Create an addDependent(String firstName, String lastName) method that instantiates a dependent using the provided names and the this reference for the third parameter to the Dependent constructor (the Employee reference)
- The addDependent method should then put the new dependent at the numDependents location in the array, and increment numDependents, but only if numDependents is less than the length of the array
- Add the method listed below to the Employee class (you
can copy it from the solution):
public String listDependents() { StringBuffer temp = new StringBuffer(); String newline = System.getProperty("line.separator"); if (newline == null) newline = "\n"; for (int i = 0; i < dependents.length; i++) { temp.append(dependents[i].getFirstName()); temp.append(" "); temp.append(dependents[i].getLastName()); temp.append(newline); } return temp.toString(); } - In your data-populating loop, add a question about how many dependents
- Use a loop to get the names and add each dependent to the employee
- When you print out the Employee information, also print out the result of calling listDependents
Typecasting with Arrays of Primitives
It is not possible to typecast an array of one type of primitive to an array of another type of primitive. For example, the following will cause compiler errors if the comment marks are removed:
Code Sample: Java-Arrays/Demos/ArrayTypecast.java
// typecasts with arrays
public class ArrayTypecast {
public static void main(String[] args) {
int i = 5;
double d;
d = i;
i = (int) d;
int inums[] = { 1, 2, 3, 4, 5 };
double[] dnums;
// line below fails
//dnums = inums;
dnums = new double[] { 1.1, 2.2, 3.3, 4.4 };
// line below fails
//inums = (int[]) dnums;
}
}
Neither an implicit or explicit typecast can be performed. With a single int i, the copy of it that is given to d can be expanded to a double. But, with the int[] inums, the value that would be given to dnums is just a copy of the reference to inums, so there is no way that each of the individual elements can be expanded to double.
The next chapter will discuss typecasting from arrays of one type of object to another.
Arrays Conclusion
In this lesson of the Java tutorial you have learned how to declare, instantiate and work with arrays of primitives and objects.