Introduction to Objects
2.11 Array of Objects
In Java, a String is an object. Therefore, an array of Strings is, in fact, an array of objects. However, a String is a special kind of object in Java and, in some ways, is treated differently from other objects. For one thing, a String is immutable; we cannot change its value. For another, we think of a String as having one field—the characters in the string—whereas a typical object will have several. For these reasons, we take a look at arrays of objects other than Strings.
Consider the class Part defined previously. The class contains two instance variables defined as follows:
public class Part {
private String name; // instance variable private double price; // instance variable // methods and static variables
} //end class Part
It is helpful to recall what happens when we declare a Part variable p as in the following:
Part p;
First, remember that p can hold the address of a Part object, not an object itself. The declaration simply allocates storage for p but leaves it undefined. We can assign the null value to p, with this:
p = null;
We can also create a Part object and assign its address to p with this statement:
p = new Part("Air Filter", 8.75);
Now consider the following declaration:
Part[] part = new Part[5];
This declares an array called part with 5 elements. Since they are object variables, these elements are guaranteed by Java to be set to null. As yet, no Part objects have been created. We can create objects and assign them individually to each element of part, as follows:
part[0] = new Part("Air Filter", 8.75);
part[1] = new Part("Ball Joint", 29.95);
part[2] = new Part("Headlamp", 36.99);
part[3] = new Part("Spark Plug", 5.00);
part[4] = new Part("Disc Pads", 24.95);
The array part can now be pictured as shown in Figure 2-10.
name: Air Filter price: 8.75
name: Ball Joint price: 29.95
name: Headlamp price: 36.99
name: Spark Plug price: 5.00
name: Disc Pads price: 24.95 part[0]
part[1]
part[2]
part[3]
part[4]
Figure 2-10. An array of Part objects
Each element of part contains the address of the corresponding object.
Remember that, in general, each element of an array can be treated in the same way as a simple variable of the array type. For instance, part[2] can be treated in the same way as p, above. And just as we can write p.setPrice(40.00), we can write part[2].setPrice(40.00) to change the price of Headlamp to 40.00.
How do we refer to the fields of a Part object? As usual, it depends on whether the code is being written inside the class Part or outside of it. If inside, the code can access the instance variables name and price directly, for example, part[2].name. If outside, it must use the accessor and mutator methods to get and set the values in the fields, for example, part[2].getName().
If we have to deal with hundreds of parts, it would be better to store the parts’ data in a file (parts.dat, say) and read them into the array using a for or while loop. Suppose the data above was stored in the file like this (we write the part name as one word so it can be read with next from the Scanner class):
AirFilter 8.75 BallJoint 29.95 Headlamp 36.99 Spark Plug 5.00 DiscPads 24.95
We can set up the part array with the following code:
Scanner in = new Scanner(new FileReader("parts.dat"));
Part[] part = new Part[5];
for (int h = 0; h < part.length; h++)
part[h] = new Part(in.next(), in.nextDouble());
This code is much better and more flexible. To read 1,000 parts, we just need to change the declaration of part and supply the data in the file. The code above remains unchanged. As usual, we don’t have to fill the entire array with parts data. We can read data until some end-of-data marker (End, say) is reached.
If we need to print the parts’ data, we could use the following:
for (int h = 0; h < part.length; h++) part[h].printPart();
Suppose we want to interchange two parts in the array, for example, part[2] with part[4]. We do it the same way we would interchange the values of any two variables of the same type, like this:
Part p = part[2];
part[2] = part[4];
part[4] = p;
It is useful to note that the actual objects remain where they were originally stored. All we do here is exchange the addresses stored in part[2] and part[4]. In Figure 2-10, think of the arrows as being interchanged.
2.11.1 Finding the Part with the Lowest Price
Suppose we want to find the part with the lowest price (in one sense, we want to find the “smallest” object). Assuming we are writing this code outside the class Part, we can write getLowestPrice to return the position of the part with the lowest price as follows:
public static int getLowestPrice(Part[] part, int lo, int hi) { // return the position of the part with the lowest price
// from part[lo] to part[hi], inclusive int small = lo;
for (int h = lo + 1; h <= hi; h++)
if (part[h].getPrice() < part[small].getPrice()) small = h;
return small;
} //end getLowestPrice
If we were writing inside the class Part, we could leave the method as it is. But since we now have direct access to the instance variables, we could replace the if statement with this one:
if (part[h].price < part[small].price) small = h;
To print the name of the part with the lowest price, we could write this:
System.out.printf("\nPart with lowest price: %s\n",
part[getLowestPrice(part, 0, part.length-1)].getName());
As an exercise, write a function to return the item with the highest price.