last updated 1/23/07
Java refers to or implements these as primitive types.
Java implements data structures as an object.
Domain:
Structure: There is a 1-1 relationship between each index and an array component (element). Index 0 selects the first element, 1 the second, etc.
Operations: [i] references the array element. Values may be assigned (written or stored) or retrieved (read or returned).
An array differs from a class in the following three ways:

Linear- every component has a unique predecessor and successor, except first and last elements.
Sequential - to access the n-th element you must access the preceding n-1 elements
Direct (random) - any element can be accessed without accessing its predecessor or successor
From the taxonomy this structure is linear - direct access - homogeneous
In Java we define an array with the following syntax:
type arrayname [ ] = new
type [n-elements];
or type [ ] arrayname = ...
Formally the array ADT is defined as
Domain:
Structure:
Operations:
Other operations such as remove or insert are not available because there are always values in the array. They really can never be removed.
The notation array[i] is implemented as follows
| index [i] |
address | value |
|---|---|---|
| 0 | 5e70 (24176) |
10 |
| 1 | 5e74 (24180) | -1 |
| 2 | 5e78 (24184) | 50 |
| 3 | 5e7c (24188) | 100 |
| 4 | 5e80 (24192) | 30 |
| 5 | 5e84 (24196) | 35 |
FORTRAN, COBOL, C/C++, Pascal are languages that support only static arrays.
In these languages the programmer must establish at program writing time, the size of the array. The array is allocated and the size cannot be changed. The programmer then also has to track the number of elements actually used and maybe has to include code to verify that the index is not ever too large.
Java and other modern languages support dynamic arrays. Here arrays are created just as any object can be created. The size can be optimally determined as needed if at all possible.
int array[];
int size = Integer.parseInt(
JOptionsPane.showInputDialog("Enter size of array: "));
array = new int[size];
...
However, if you want to extend or shrink the array, you need to create a second array and copy the references over. This should be done on a limited basis because of the linear complexity nature of the copy operation. That is, the copy time may not really benefit the little bit of memory that you are saving.
In order to avoid the cost of resizing the array, it usually is beneficial to have an array that is larger than needed (if at some point you need to make it larger, you can) but you track the number of elements needed.
public static final int MAX_SIZE = 100; //physical size (final says no change permitted)
private Object[] array; //name of array private int nObjects; //logical size
public dataModel(){ //default constructor
array = new Object[MAX_SIZE];
nObjects = 0;
}
public dataModel(int size){ // constructor
if(size<0 || size>MAX_SIZE) size = MAX_SIZE;
array = new Object[size];
nObjects = 0;
}
Increasing an array by one or decreasing by one requires copying the entire array over to the new sized array. Very inefficient over time. In fact, the overall algorithm, if it were meant to be linear would then be quadratic, or that the algorithm complexity is increased by a factor of n.
Generally if you need to increase the size of an existing array, consider increasing it by some factor such as doubling or 50%. This will result in a complexity factor increase to be logarithmic. (So a linear O(n) program becomes O(n log n)).
//want to add an element to array; check if room
if(nObjects == array.length){
Object temp [] = new Object[array.length*2]; //double the size
for(int i=0; i<nObjects; i++){ // copy the old array over
temp[i] = array[i];
}
array = temp; //keep new array and lose the old (garbage)
}
//now add the element by shifting other elements
//to make room in the right position
Decreasing the array should be done when the array utilization is substantially smaller than the increasing factor. What could happen if you decrease by the same factor?
//want to delete an element
//delete by shifting elements
...
//check if logical size has reached a threshold
if(nObjects == array.length/4 && nObjects>DEFAULT_SIZE){
Object temp [] = new Object[array.length/2];
for(int i=0; i<nObjects; i++){ // copy the old array over
temp[i] = array[i];
}
array = temp; //keep new array and lose the old
}
Ways of combining built-in types and classes into versatile hierarchies:
Suppose we define:
public class Point
{ //record structure -- note the public definition
public int xValue;
public int yValue;
}
Then, we could define a new circle class as:
Public class NewCircle
{
public Point location;
public float radius;
public boolean solid;
}
NewCircle[] allCircles = new NewCircle[10]; allCIrcles[0] = new NewCircle(); allCircles[0] = myNewCircle; allCircles[1] = new NewCircle(); allCircles[1].location = new Point(); allCircles[1].location.xValue = 6; allCircles[1].location.yValue = 6; allCircles[1].radius = 1.3f; allCircles[1].solid = false;

Arrays of objects are denoted with [ ]. The brackets can be placed either after the type/class or after the array variable. The name of the array is an array variable.
You need to instantiate the array. BUT you simply get an array of references that are ready to be assigned to instances of the plain objects.
Circle [] circles; //declare the array variable circles = new Circle[10]; //instantiate an array of references circles[0] = new Circle (1,1,2); //populate circles[1] = new Circle (2,2,3);
Shape shapes[] = new Shape[10]; //declare and instantiate shapes[0] = new Circle(1,2,3); //populate shapes[1] = circles[1]; shapes[2] = new Rectangle(2,3,4,4); shapes[3] = circles[0]; shapes[4] = new Rectange(3,4,5,1);
Here's the real power of an object oriented language. You use polymorphic names to represent the same concept or operation across several classes in a hierarchy.
totalArea = 0;
for(i=0; i<10; i++){//scan whole array
totalArea = shapes[i].area();
} // there's no need to know which area function is used
for(i=0; i<10; i++){
System.out.println(shape[i]);
}
There are times you need to
To test for a subclass, use the instanceof operator.
BUT the compiler wants to verify that operations will be legal. You need to help the compiler know the operation will be legitimate. Use type casting as in (ClassName)variable
if(shapes[i] instanceof Circle){
System.out.println("Circle "+(i+1)+"has radius "+
((Circle)shapes[i]).getRadius()+"\n");
}
The Java class/object really implements this implicitly with objects and instance variables.
From the taxonomy this structure is linear - direct access - heterogeneous.
The components of a record are usually called fields each referenced by a fieldname.
Domain:
Each record consists of
Structure:
Operations:
C/C++ has a struct "structure" as its record capability. We will explore this more later.