4.7 Collection Classes in Java

 < Day Day Up > 



4.7 Collection Classes in Java

4.7.1 Arrays in Java

Arrays in Java are very different than arrays in C/C++. In C/C++, arrays are little more than pointers to a block of memory, and the operations to access them are defined at compilation time. In that way, arrays in C/C++ are very much like primitive data types. In Java, arrays have some primitive support to access members using the "[ ]" operators, but are different in that they are more like first-class objects with some extra syntax built into the language to manipulate them. Thus, using arrays in Java is different than using arrays in C/C++.

Arrays in any language are contiguous pieces of memory that hold a set of values. The size of the data types stored in an array must be constant to allow the individual members of the array to be directly accessed. Because the data in the array must be a constant size, arrays in Java are most useful for primitive data. This is true, first, because with primitive data, the size of each data item is fixed, so the actual data items can be created when the array is created. Also, because the data items are stored in the array, arrays are useful with primitives because they can be directly accessed by normal array-addressing mechanisms of calculating a base address and an offset. Neither of these two advantages holds for arrays of objects.

Note that, while an array of primitives is a list of data values, the array itself still behaves largely as an object. For example, consider Exhibit 16 (Program4.11), which allocates an array of primitives, in this case ints, and writes the array to a file using an ObjectOutputStream. This program shows that arrays are like objects in Java in the following ways:

  • The memory (or variable) for the array cannot be allocated at the same time that the identifier for the array is declared. Just as with objects, memory for the array must be allocated with a "new" statement, and is stored in the heap.

  • Arrays are stored with information about the number of elements in the array, and that information can be accessed and used at runtime. The loop in this program gets its range by querying the "length" variable of the array. Accesses to members of the array are checked, as shown when an OutOfBoundsException is generated.

  • As with objects, all elements in the array are initialized to 0 or null. In the case of arrays of primitives, all elements are initialized to 0.

  • Arrays can be serialized. This shows that the memory allocation properties that were true of other objects also apply to arrays.

Exhibit 16: Program4.11: Allocating an Array of Primitives

start example

 import java.io.*; public class ArrayOfPrimitives {   public static void main(String args[]) {     try {       int array[] = new int[10];       ObjectOutputStream oos = new ObjectOutputStream (       new FileOutputStream("temp.dat"));       oos.writeObject(array);     } catch (IOException ioe) {       ioe.printStackTrace();     }   } } 

end example

So, arrays in Java take on the properties of objects, even when they store primitives. In fact, other than to store arrays of primitives, which cannot be achieved with container classes, using arrays as opposed to container classes in Java offers few advantages.

4.7.2 Arrays of Objects

In Java, because any class (except a class that is declared final) can be overridden, the size of an object to be stored at runtime cannot be guaranteed by the type; thus, it is not possible to store objects directly in an array. Instead, arrays of objects in Java store references (normally addresses) to the individual objects, so the array and objects must be allocated separately, as shown in Exhibit 17 (Program4.12). This makes arrays less useful for objects, and means that collection classes, such as Vector, are normally used when storing collections of objects. Using collection classes will remove any ambiguity that surrounds arrays as to whether they are objects or not because collection classes will be first-class objects. Arrays in Java can be used to store either primitives or objects. For primitives, arrays are a useful construct; however, arrays of objects are less useful and have largely been replaced by collection classes, which are covered in Section 4.7.3. This section explains arrays of objects and why collection classes were developed.

Exhibit 17: Program4.12: Allocating an array of objects

start example

 class Person { } class Car { } public class ArrayOfObjects {   public static void main(String args[]) {     Object array[] = new Object[10];     array[0] = new Person();     array[1] = new Car();     array[2] = new Object();     //array[3..9] is unallocated.   } } 

end example

When arrays of objects are allocated, only the references for the objects are created; no objects are actually created. The actual objects to be stored must be allocated individually at runtime. While this might appear to be a negative, it allows objects of any type to be stored in an array of objects. One significant problem with storing arrays of amorphous objects in some languages other than Java is that the compiler needs to know the type of the object in order to generate the machine code required to manipulate it at runtime. If objects are stored in an array, it is not possible to determine the type of the object when it is taken from the array. The best that can be done is that the programmer can guess what the object will be and cast the object so that the compiler can generate code for the data type that the programmer thinks is stored. Thus, many languages do not include classes for containers of generic objects. However, thanks once again to the runtime data type tag, using object arrays is perfectly safe because the runtime data tag allows the JVM to identify the type of object stored when it is accessed at runtime.

For example, Exhibit 18 (Program4.13) shows an example of an array of objects in which a Person object and a Car object are stored and retrieved. Despite the apparent simplicity of this program, what is happening is really quite amazing. First, the array of objects is created and all of the objects are initialized to null. This array can take objects of any type and will correctly handle them. Next, several objects of different data types (in this case, an object, a Person, and a Car) are added to the array in an order that can only be determined at runtime. The compiler cannot determine which objects are stored in the array because the order in which they are stored is completely determined by the random variable at runtime. Later, the elements in the array are retrieved and their toString methods are called. The correct toString method is called for each object, including the null elements, because the runtime data type tag allows the JVM to select the correct data type for each object and to dispatch the correct function for that type. This process of calling correct methods at runtime based on the runtime data type is discussed in more detail in Chapter 5; however, this example demonstrates that knowing the data types at runtime is a very powerful mechanism that allows storage of objects of unknown data types.

Exhibit 18: Program4.13: Array of Objects

start example

 class Person { } class Car { } public class RandomCreate {   public static void main(String args[]) {     Object object;     //Randomly choose to create a Car or     //Person Object.     int flag = (int)(2.0 * Math.random());     if (flag = = 0)       object = new Car();     else       object = new Person();     //Cast to the correct Object     if (object instanceof Person) {       Person person = (Person)object;     }     else if (object instanceof Car) {       Car car = (Car)object;     }   } } 

end example

Because arrays are already almost objects, it would be handy to add a number of operations to their definition. For example, it would be nice to be able to find any element by its value, not just its position. It would also be nice to be able to insert an element into an array without having to include logic to move all the other elements to make room for the new one. A programmer might want the array to be sorted or have keys to look up objects. The developers of Java recognized that the limited capabilities of an array could be greatly improved in these ways and so included in the language a number of classes that enhance the ability of an array to handle collections of objects. In the next section, we look at one of these classes, a collection class called a Vector.

4.7.3 Collection Classes

A collection class is simply a class that allows collections of disparate object types to be stored inside a single object. It is very similar to an array of objects, except that collection classes generally have more functionality included in the class than can be included in an array. For example, one specific type of a collection is the class Vector. A Java Vector is an array that grows as needed to make sure there is always space when an element is added. It also incorporates additional functionality, such as allowing elements to be added at any place in the array, and allows the elements to be manipulated by the object rather than the index. Exhibit 19 (Program4.14) shows an example of using the Vector to store and retrieve objects. Two special functions have been included from the Vector class for this program. The first inserts a record into the table and uses the Vector's add method to add an element in the second component in the Vector, causing all other elements in the Vector to be moved one position forward one position. The second function finds the object in the Vector using the indexOf method, taking advantage of the searching capability of the Vector to find the item.

Exhibit 19: Program4.14: Example of Using a Vector Class

start example

 import java.util.Vector; class Person {   private String name;   public Person() {   }   public Person(String name) {     this.name = name;   }   public boolean equals(Object object) {     return this.name.equals(((Person)object).name);   }   public String toString() {     return name;   }   public String getName() {     return name;   }   public void setName(String name) {     this.name = name;   } } public class ShowVector {   private static Vector People = new Vector();   public static void main(String args[]) {     people.add(new Person("Chuck"));     people.add(new Person("Patty"));     people.add(new Person("Linda"));     //Note that this line puts the new record in at     //component 2 in the vector and moves everything     //else down one place in the vector.     people.add(1, new Person("Cindy"));     //Print the vector to show that the add worked.     for (int i = 0; i < people.size(); i++) {       System.out.println("Person = "+ people.elementAt(i));     }     //Now find the record "Chuck"     int elementNo = people.indexOf(new Person("Chuck"));     System.out.println("Chuck at "+ elementNo);   } } 

end example

The many different types of collections allow for special functionality in the collection. For example, maps allow objects to be accessed by a key, and sets ensure that no duplicate elements are in a collection. Many different predefined collection classes implement these types of collections, and each implements the collection in ways that help with the problem. When using the predefined collections classes in Java, specific methods have to be defined. These override methods in class Object, such as equals and hashcode, or implement interfaces, such as Comparable. For example, in Exhibit 19 (Program4.14) the Person class has to implement an equals method to allow the program to work correctly. If the equals method had not been implemented, the Vector class would have used the Object's equals method to compare the two Person objects; however, because they are equivalent but not the same object, it would have failed to have found the object.



 < Day Day Up > 



Creating Components. Object Oriented, Concurrent, and Distributed Computing in Java
The .NET Developers Guide to Directory Services Programming
ISBN: 849314992
EAN: 2147483647
Year: 2003
Pages: 162

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net