Arrays
Collection classes
Since most programs involve gathering, manipulating and presenting information,
it is important to know ways to organize the data objects we have.
Java supports a number of different container mechanisms.
Classes are the simplest kind of container.
Each instance of a class can hold a variety of data values and
methods to act on them.
Arrays are the simplest container that holds more than one object.
It features fast access, but it is fixed in length and
is slow to insert or delete elements.
Arrays
Arrays are the oldest and simplest kind of container.
An array is a set of variables, placed sequentially in memory.
All the variables are of the same type.
Once an array is defined, it doesn't get any longer or shorter.
You can make arrays of any type in Java.
The individual variables in the set are accesses by using their
index.
Array indices in Java start at 0.
So a 5 element array has elements numbered from 0 to 4.
Arrays are declared using this syntax.
type[] variable_name;
As in other kinds of objects, this doesn't actually create the array,
this makes a reference.
So to make a 5 element integer array, we do
int[] foo = new int[5];
This creates a block of memory big enough to hold 5 integers.
It would look like this:
Note that there are no data values in the elements.
The arrays is not initialized.
The object that represents the array has a length field in it
that holds the number of elements in the array.
To use an individual element of the array, we use subscript notation.
This just involves putting an index between two square brackets after the
array name.
Here are some examples.
int x = foo[2];
foo[3]=9;
int y = foo[x];
for(int i = 0; i< foo.length; i++)
foo[i] += 6;
Java arrays are automatically perform bounds checking.
This means that every time you reference an array element, the system checks
that you are not outside the bounds of the array.
The bounds are indices between 0 and the length-1 of the array.
In our example array, references like foo[-1] or foo[10] would
cause an exception.
Java supports multi-dimensional arrays.
The example above is a one-dimensional array.
A table is an example of a 2D array.
Each row in the array will usually have the same number of columns.
This is not required because Java represents 2D (and higher) arrays
as an array of arrays.
Remember that arrays are objects and you can make an array of any object.
So you create an array where every element is an array object.
Since the array object is a reference to an array, each one
could be a different length.
To create a 2D array, you declare it much like the 1D example.
int[][] foo = new int[3][4];
This creates a 2D array of 3 rows and 4 columns.
Here are some examples of using a 2D array.
int x = foo[2][1];
foo[3][0]=9;
int y = foo[x][0];
for(int i = 0; i< foo.length; i++)
for(int j = 0; j< foo[i].length; j++)
foo[i][j] += 6;
You can go to higher dimensionality.
Just keep adding pairs of square brackets.
A use for this would be to represent data that is organized along
several axes.
If you recorded the temperature at a number of different locations,
you could have a 4D array of data.
Something like data[latitude][longitude][altitude][temperature].
Array odds and ends
Arrays can be initialized.
A 1D array of integers could be initialized like this.
int[] ages={12,47,45,9,3,3};
The data inside the braces is called an initializer.
This syntax can only be used when an array is first declared.
Also note that there is no call to the new operator.
Initializers can be used with multi-dimensional arrays.
You simply nest them.
For example,
int[][] foo = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
Each of the nested initializers represents one row in the array.
Arrays can be passed as parameters.
Since the array name is a reference to the array, what is passed
is not a copy of the array, but a copy of the reference.
This means that if you alter an array element inside a method,
you are changing the value in the original array.
Arrays of objects
When creating an array of objects (class instances rather than
primitive types like integers), the creation of the array and the creation
of the objects are two separate things.
Here is a short example
public class objarray
{
public static void main(String[] args)
{
String[] foo = new String[10]; // make 10 String objects
System.out.println(foo[1].length());
} // main
} // objarray
This compiles correctly but when it is run, we get
>>javac objarray.java
>>java objarray
Exception in thread "main" java.lang.NullPointerException
at objarray.main(objarray.java:6)
This is because while we have created 10 String references,
we haven't create any Strings.
Let's create some strings and try again.
public class objarray
{
public static void main(String[] args)
{
String[] foo = new String[10]; // make 10 String objects
for(int i=0; i < foo.length;i++) {
foo[i] = new String(Integer.toString(i*2));
} // for
for(int i=0; i < foo.length;i++) {
System.out.println("foo[" + i + "](" + foo[i] +
") length = " + foo[i].length());
} // for
} // main
} // objarray
The output from this is
>>javac objarray.java
>>java objarray
foo[0](0) length = 1
foo[1](2) length = 1
foo[2](4) length = 1
foo[3](6) length = 1
foo[4](8) length = 1
foo[5](10) length = 2
foo[6](12) length = 2
foo[7](14) length = 2
foo[8](16) length = 2
foo[9](18) length = 2
Array details
This is a bit about how arrays are implemented and used at a low level.
The type of the elements is know as the base type.
The objects in an array can be of any type as
long as they are all the same.
The size of an array is fixed at compile time.
Since the elements are contiguous, we can directly
calculate the address of any elements
given three pieces of information.
Addressing
We need the size of the elements, the address of the first element and the
number of the element in the array.
The expression for doing this is:
initial_address + (element#) * size_of_base_type
For example, if we had an array of integers (each four bytes long) that
started at address 15, the location in memory
(the address) of element 10 is
15 + (10) * 4 = 55
Arrays in Java start with an element number of 0.
This is important to
remember as people usually start counting at 1.
Multi-dimensional Arrays
Multi-dimensional arrays are stored as sequences of one dimensional arrays.
An NxM array has N rows and M
columns.
Either each row is stored (row major) or each column (column major).
The calculation above is extended again to first find the row we want by
changing element# to row# and
size_of_object to size_of_row.
This gives us the initial address of the row we want and we use
exactly the first
version of the expression to calculate the
column address.
First the row address
initial_address + (row# - initial_row#) * size_of_row
Then find the column within that row
row_address + (element# - initial_element#) * size_of_base_type
Arrays are characterized by fast random access.
Any element on the array can be found as fast as any other.
They are however, limited to the size
originally allocated and all the elements must be the same size.
It is also difficult to insert or delete elements.