Its a fairly simple program that has only a fixed quantity of objects with known lifetimes.
In general, your programs will always be creating new objects based on some criteria that will be known only at the time the program is running. You wont know until run time the quantity or even the exact type of the objects you need. To solve the general programming problem, you need to be able to create any number of objects, anytime, anywhere. So you cant rely on creating a named reference to hold each one of your objects:
since youll never know how many of these youll actually need.
Most languages provide some way to solve this rather essential problem. Java has several ways to hold objects (or rather, references to objects). The built-in type is the array, which has been discussed before. Also, the Java utilities library has a reasonably complete set of container classes (also known as collection classes, but because the Java 2 libraries use the name Collection to refer to a particular subset of the library, I shall also use the more inclusive term container). Containers provide sophisticated ways to hold and even manipulate your objects.
Most of the necessary introduction to arrays is in the last section of Chapter 4, which showed how you define and initialize an array. Holding objects is the focus of this chapter, and an array is just one way to hold objects. But there are a number of other ways to hold objects, so what makes an array special?
There are three issues that distinguish arrays from other types of containers: efficiency, type, and the ability to hold primitives. The array is the most efficient way that Java provides to store and randomly access a sequence of object references. The array is a simple linear sequence, which makes element access fast, but you pay for this speed; when you create an array object, its size is fixed and cannot be changed for the lifetime of that array object. You might suggest creating an array of a particular size and then, if you run out of space, creating a new one and moving all the references from the old one to the new one. This is the behavior of the ArrayList class, which will be studied later in this chapter. However, because of the overhead of this flexibility, an ArrayList is measurably less efficient than an array.
In C++, the vector container class does know the type of objects it holds, but it has a different drawback when compared with arrays in Java: The C++ vectors operator doesnt do bounds checking, so you can run past the end. In Java, you get bounds checking regardless of whether youre using an array or a container; youll get a RuntimeException if you exceed the bounds. This type of exception indicates a programmer error, and thus you dont need to check for it in your code. As an aside, the reason the C++ vector doesnt check bounds with every access is speed; in Java, you have the constant performance overhead of bounds checking all the time for both arrays and containers.
The other generic container classes that will be studied in this chapter, List, Set, and Map, all deal with objects as if they had no specific type. That is, they treat them as type Object, the root class of all classes in Java. This works fine from one standpoint: You need to build only one container, and any Java object will go into that container. (Except for primitives, which can be placed in containers as constants using the Java primitive wrapper classes, or as changeable values by wrapping in your own class.) This is the second place where an array is superior to the generic containers: When you create an array, you create it to hold a specific type (which is related to the third factoran array can hold primitives, whereas a container cannot). This means that you get compile-time type checking to prevent you from inserting the wrong type or mistaking the type that youre extracting. Of course, Java will prevent you from sending an inappropriate message to an object at either compile time or run time. So its not riskier one way or the other, its just nicer if the compiler points it out to you, faster at run time, and theres less likelihood that the end user will get surprised by an exception.
For efficiency and type checking, its always worth trying to use an array. However, when youre solving a more general problem, arrays can be too restrictive. After looking at arrays, the rest of this chapter will be devoted to the container classes provided by Java.