The array identifier is actually a handle to a real object, regardless of the type of array used. Those objects themselves are created in the memory "heap". The heap object can be created implicitly (that is, by default), or "explicitly" (that is, explicitly specified, with a new expression). Part of the heap object (actually the only field or method we can access) is a read-only length (length) member, which tells us how many elements can be accommodated in that array object. For array objects, the [] syntax is the only alternative access method we can use.
The following example shows the different ways in which arrays are initialized, and how array handles are assigned to different array objects. It also reveals that the array of objects and the base data type arrays are almost identical in the way they are used. The only difference is that the object array holds the handle, and the base data type array holds the specific values (refer to the "Assignments" section in chapter 3rd, if you are having difficulty executing this program):
: Arraysize.java//initialization & re-assignment of arrays package c08; Class Weeble {}//A small mythical creature public class ArraySize {public static void main (string[] args) {//A Rrays of objects:weeble[] A; Null handle weeble[] B = new Weeble[5];
Null handles weeble[] c = new Weeble[4];
for (int i = 0; i < c.length i++) c[i] = new weeble ();
Weeble[] D = {new Weeble (), New Weeble (), New Weeble ()}; Compile error:variable a not initialized://!
System.out.println ("a.length=" + a.length);
System.out.println ("b.length =" + b.length);
The handles inside the array are//automatically initialized to null:for (int i = 0; i < b.length; i++)
System.out.println ("b[" + i + "]=" + b[i]);
System.out.println ("c.length =" + c.length);
System.out.println ("d.length =" + d.length);
A = D;
System.out.println ("a.length =" + a.length);
Java 1.1 Initialization syntax: A = new weeble[] {new weeble (), New Weeble ()};
System.out.println ("a.length =" + a.length); Arrays of primitives:int[] e;
Null handle int[] f = new int[5];
Int[] g = new int[4];
for (int i = 0; i < g.length i++) g[i] = I*i;
Int[] H = {11, 47, 93}; Compile error:variable e not initialized://!
System.out.println ("e.length=" + e.length);
System.out.println ("f.length =" + f.length);
The primitives inside the array are//automatically initialized to zero:for (int i = 0; i < f.length; i++)
System.out.println ("f[" + i + "]=" + f[i]);
System.out.println ("g.length =" + g.length);
System.out.println ("h.length =" + h.length);
e = h;
System.out.println ("e.length =" + e.length);
Java 1.1 Initialization syntax:e = new int[] {1, 2};
System.out.println ("e.length =" + e.length); }
} ///:~
Here's the output from the program:
B.length = 5
b[0]=null
b[1]=null
b[2]=null
b[3]=null b[4]=null c.length
= 4
d.length = 3
a.length = 3
a.length = 2
f.length = 5
f[0]=0
f[1]=0
f[2]=0 f[3]=0
g.length = 4
h.length = 3
e.length = 3
e.length = 2
Where array A is initialized to a null handle. At this point, the compiler will prevent us from doing anything practical with this handle unless it has been properly initialized. Array B is initialized to point to an array of weeble handles, but no weeble objects are actually placed in that array. However, we can still query the size of that array because B points to a legitimate object. This also poses a problem for us: it is not known how many elements are actually contained in that array, because length only tells us how many elements can be placed into that array. In other words, we know only the size or capacity of an array object, and we don't know how many elements it actually holds. However, because an array object is automatically initialized to null at the be made early of creation, you can check whether it is null and determine whether a particular array "empty" holds an object. Similarly, an array of base data types is automatically initialized to 0 (for numeric types), null (character type), or False (Boolean type).
The array C shows that we first create an array object, and then assign the Weeble object to all the "vacancies" in that array. Array d reveals the "set initialization" syntax, creating an array object (explicitly with the new command, similar to array c), and then initializing with the Weeble object, all working in a single statement.
Here's an expression:
A = D;
Shows us how to get the handle of the connection to the same array object and assign it to another array object, just as we do with any other type of object handle. Now, A and d all point to the same array object within the memory heap.
Java 1.1 Adds a new array initialization syntax that can be imagined as "dynamic collection initialization." The Java 1 collection initialization method used by D must be done at the same time as defining D. But with the syntax of Java 1.1, you can create and initialize an array object anywhere. For example, assuming the hide () method is used to get an array of weeble objects, the traditional method of calling it is:
Hide (d);
In Java 1.1, however, you can also dynamically create an array that you want to pass as a parameter, as follows:
Hide (new weeble[] {new weeble (), New Weeble ()});
This new syntax makes it more convenient for us to write code in some situations.
The second part of the above example reveals the problem: for arrays of basic data types, they work in a way that is very similar to an array of objects, but the former directly accommodates data values of the underlying type.
1. Basic Data Type Collection
Collection classes can only hold object handles. But for an array, it can hold both the basic type of data directly and the handle to the object. You can place the value of the base data type into a collection using the wrapper class like integer or double. But as the Wordcount.java example illustrates later in this chapter, the wrapper class for the base data type only works in some situations. Whether you place a base type of data into an array or encapsulate it into a class that is in a collection, it involves the problem of execution efficiency. Obviously, if you can create and access an array of basic data types, the former is much more efficient than accessing a collection of encapsulated data.
Of course, if you're prepared for a basic data type, and you want the flexibility of the set (automatically expand and make more space when you need it), it's not appropriate to use arrays, you must use a collection of encapsulated data. You might think that there should be a special type of vector for each of the basic data types. But Java does not provide this feature. Some forms of modeling might help Java to better solve the problem one day (comment ①).
①: Here is a place where C + + is doing better than Java, because C + + provides support for "parameterized types" through the template keyword.