Published: March 4, 2002
By Richard G. Baldwin
Purpose
The purpose of this miniseries is to help you study for the Advanced Placement Examinations designed by the College Board.
Once you understand everything in this miniseries, plus the material in the lessons that I published earlier on Java Data Structures, you should understand the Java programming features that the College Board considers essential for the first two semesters of object-oriented programming education at the university level.
Approach
These lessons provide questions, answers, and explanations designed to help you to understand the subset of Java features covered by the Java Advanced Placement Examinations (as of October, 2001).
Please see the first lesson in the miniseries entitled Java Advanced Placement Study Guide: Introduction to the Lessons, Primitive Types, for additional background information. The previous lesson was entitled Java Advanced Placement Study Guide: Escape Character Sequences and Arrays.
Supplementary material
In addition to the material in these lessons, I recommend that you also study the other lessons in my extensive collection of online Java tutorials, which are designed from a more conventional textbook approach. You will find those lessons published at Gamelan.com. However, as of the date of this writing, Gamelan doesn't maintain a consolidated index of my Java tutorial lessons, and sometimes they are difficult to locate there. You will find a consolidated index at Baldwin's Java Programming Tutorials.
What is Included?
Click here for a preview of the Java
programming features covered by this lesson.
public class Ap064{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ double[] A = new double[2]; A[0] = 1.0; A[1] = 2.0; Object B = A; System.out.println("I'm OK"); }//end doArrays() }// end class |
2. What output is produced by the following program?
public class Ap065{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ double[] A = new double[2]; A[0] = 1.0; A[1] = 2.0; Object B = A; System.out.println( B[0] + " " + B[1]); }//end doArrays() }// end class |
3. What output is produced by the following program?
public class Ap066{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ double[] A = new double[2]; A[0] = 1.0; A[1] = 2.0; Object B = A; double C = (double)B; System.out.println( C[0] + " " + C[1]); }//end doArrays() }// end class |
4. What output is produced by the following program?
public class Ap067{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ double[] A = new double[2]; A[0] = 1.0; A[1] = 2.0; Object B = A; double[] C = (double[])B; System.out.println( C[0] + " " + C[1]); }//end doArrays() }// end class |
5. What output is produced by the following program?
public class Ap068{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ double[] A = new double[2]; A[0] = 1.0; A[1] = 2.0; Object B = A; String[] C = (String[])B; System.out.println( C[0] + " " + C[1]); }//end doArrays() }// end class |
6. What output is produced by the following program?
public class Ap069{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ Subclass[] A = new Subclass[2]; A[0] = new Subclass(1); A[1] = new Subclass(2); System.out.println( A[0] + " " + A[1]); }//end doArrays() }// end class class Superclass{ private int data; public Superclass(int data){ this.data = data; }//end constructor public int getData(){ return data; }//end getData() public String toString(){ return "" + data; }//end toString() }//end class SuperClass class Subclass extends Superclass{ public Subclass(int data){ super(data); }//end constructor }//end class Subclass |
7. What output is produced by the following program?
public class Ap070{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ Subclass[] A = new Subclass[2]; A[0] = new Subclass(1); A[1] = new Subclass(2); Superclass[] B = A; System.out.println( B[0] + " " + B[1]); }//end doArrays() }// end class class Superclass{ private int data; public Superclass(int data){ this.data = data; }//end constructor public int getData(){ return data; }//end getData() public String toString(){ return "" + data; }//end toString() }//end class SuperClass class Subclass extends Superclass{ public Subclass(int data){ super(data); }//end constructor }//end class Subclass |
8. What output is produced by the following program?
public class Ap071{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ Superclass[] A = new Superclass[2]; A[0] = new Superclass(1); A[1] = new Superclass(2); Subclass[] B = (Subclass[])A; System.out.println( B[0] + " " + B[1]); }//end doArrays() }// end class class Superclass{ private int data; public Superclass(int data){ this.data = data; }//end constructor public int getData(){ return data; }//end getData() public String toString(){ return "" + data; }//end toString() }//end class SuperClass class Subclass extends Superclass{ public Subclass(int data){ super(data); }//end constructor }//end class Subclass |
9. What output is produced by the following program?
public class Ap072{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ Subclass[] A = new Subclass[2]; A[0] = new Subclass(1); A[1] = new Subclass(2); Superclass[] B = A; Subclass[] C = (Subclass[])B; System.out.println( C[0] + " " + C[1]); }//end doArrays() }// end class class Superclass{ private int data; public Superclass(int data){ this.data = data; }//end constructor public int getData(){ return data; }//end getData() public String toString(){ return "" + data; }//end toString() }//end class SuperClass class Subclass extends Superclass{ public Subclass(int data){ super(data); }//end constructor }//end class Subclass |
10. What output is produced by the following program?
public class Ap073{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ double[] A = new double[2]; A[0] = 1.0; A[1] = 2.0; Object B = A; System.out.println( ((double[])B)[0] + " " + ((double[])B)[1]); }//end doArrays() }// end class |
11. What output is produced by the following program?
public class Ap074{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ int[] A = new int[2]; A[0] = 1; A[1] = 2; double[] B = (double[])A; System.out.println( B[0] + " " + B[1]); }//end doArrays() }// end class |
12. What output is produced by the following program?
public class Ap075{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ int[] B = returnArray(); for(int i = 0; i < B.length;i++){ System.out.print(B[i] + " "); }//end for loop System.out.println(); }//end doArrays() public int[] returnArray(){ int[] A = new int[2]; A[0] = 1; A[1] = 2; return A; }//end returnArray() }// end class |
13. What output is produced by the following program?
public class Ap076{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ int[] A[]; A = new int[2][3]; for(int i=0; i<A.length;i++){ for(int j=0;j<A[0].length;j++){ A[i][j] = i*j; }//end inner loop }//end outer loop for(int i=0; i<A.length;i++){ for(int j=0;j<A[0].length;j++){ System.out.print( A[i][j] + " "); }//end inner loop System.out.println(); }//end outer loop }//end doArrays() }// end class |
14. What output is produced by the following program?
public class Ap077{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ Subclass[] A = new Subclass[2]; A[0] = new Subclass(1); A[1] = new Subclass(2); Object X = A; Superclass B = A; Subclass[] C = (Subclass[])B; Subclass[] Y = (Subclass[])X; System.out.println( C[0] + " " + Y[1]); }//end doArrays() }// end class class Superclass{ private int data; public Superclass(int data){ this.data = data; }//end constructor public int getData(){ return data; }//end getData() public String toString(){ return "" + data; }//end toString() }//end class SuperClass class Subclass extends Superclass{ public Subclass(int data){ super(data); }//end constructor }//end class Subclass |
15. What output is produced by the following program?
public class Ap078{ public static void main( String args[]){ new Worker().doArrays(); }//end main() }//end class definition class Worker{ public void doArrays(){ int[] A = new int[1]; double[] B = new double[1]; boolean[] C = new boolean[1]; int[] D = new int[0]; System.out.println(A[0] + " " + B[0] + " " + C[0] + " " + D.length); }//end doArrays() }// end class |
Richard has participated in numerous consulting projects involving Java, XML, or a combination of the two. He frequently provides onsite Java and/or XML training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Java Programming Tutorials, which has gained a worldwide following among experienced and aspiring Java programmers. He has also published articles on Java Programming in Java Pro magazine.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.
"Arrays: 1-dimensional arrays and 2-dimensional rectangular arrays are part of the AP CS subset. Both arrays of primitive types (e.g. int[] and arrays of objects (e.g. Student[]) are tested. Initialization of named arrays (int[] a = { 1, 2, 3 };) is part of the AP CS subset. ... students are expected to know that a[0].length is the number of columns in a rectangular two-dimensional array a."
You can create a new array object and initialize its elements using statements similar to the following:
int[] A = {22, 43, 69};
X[] B = {new X(32), new X(21)};
What if you don't initialize array elements?
If you create a new array object without initializing its elements, the value of each element in the array is automatically initialized to a default value.
Illustrating array element default initialization
This program illustrates default initialization of int, double, and boolean arrays.
The default values are as follows:
This program also illustrates that it is possible to have an array object in Java that has no elements. In this case, the value of the length property for the array object is 0.
Give me an example
For example, when the user doesn't enter any arguments on the command line for a Java application, the incoming parameter String array to the main() method has a length value of 0.
Another example
It is also possible that methods that return a reference to an array object may sometimes return a reference to an array whose length is 0. The method must satisfy the return type requirement by returning a reference to an array object. Sometimes, there is no data to be used to populate the array, so the method will simply return a reference to an array object with a length property value of 0.
As you learned in an earlier lesson, you can assign an array object's reference to an ordinary reference variable of the type Object. It is not necessary to indicate that the reference variable is a reference to an array by appending square brackets to the type name or the variable name.
Only works with type Object
However, you cannot assign an array object's reference to an ordinary reference variable of any other type. For any type other than Object, the reference variable must be declared to hold a reference to an array object by appending empty square brackets onto the type name or the variable name.
The first statement in the following fragment
compiles successfully.
Object X = A; Superclass B = A; |
However, the second statement in the above fragment produces a compiler error under JDK 1.3, which is partially reproduced below.
Both Superclass and Object are superclasses
of the array type referred to by the reference variable named A.
However, because of the above rule, in order to cause this program to compile
successfully, you would need to modify it as shown below by adding the
requisite empty square brackets to the Superclass type name.
Object X = A; Superclass[] B = A; |
Ap077.java:22: incompatible types
found : Subclass[]
required: Superclass
Superclass B = A;
As I indicated in an earlier lesson, when declaring
a reference variable that will refer to an array object, you can place
the empty square brackets next to the name of the type or next to the name
of the reference variable. In other words, either of the following
formats will work.
int[][] A; int B[][]; |
What I didn't tell you at that time is that you can place some of the empty square brackets in one location and the remainder in the other location.
Really ugly syntax
This is indicated by the following fragment, which
declares a reference variable for a two-dimensional array of type int.
Then it creates the two-dimensional array object and assigns the array
object's reference to the reference variable.
int[] A[]; A = new int[2][3]; |
While it doesn't matter which location you use for the square brackets in the declaration, it does matter how many pairs of square brackets you place in the two locations combined. The number of dimensions on the array (if you want to think of a Java array as having dimensions) will equal the total number of pairs of square brackets. Thus, in this case, the array is a two-dimensional array because there is one pair of square brackets next to the type and another pair next to the variable name.
This program goes on to use nested for loops to populate the array and then to display the contents of the elements.
I personally don't use this syntax, and I hope that you don't either. However, even if you don't use it, you need to be able to recognize it when used by others.
This program illustrates the use of the array property named length, whose value always matches the number of elements in the array.
As a Java programmer, you will frequently invoke methods that will return a reference to an array object of a specified type, but of an unknown length. (See, for example, the method named getEventSetDescriptors() that is declared in the interface named BeanInfo.) This program simulates that situation.
Returning a reference to an array
The method named returnArray() returns a reference to an array of type int having two elements. Although I fixed the size of the array in this example, I could just as easily have used a random number to set a different size for the array each time the method is called. Therefore, the doArrays() method making the call to the method named returnArray() has no way of knowing the size of the array referred to by the reference that it receives as a return value.
All array objects have a length property
This could be a problem, but Java provides the solution to the problem in the length property belonging to all array objects.
The for loop in the method named doArrays() uses the length property of the array to determine how many elements it needs to display. This is a very common scenario in Java.
You cannot cast an array reference from one primitive type to another primitive type, even if the individual elements in the array are of a type that can normally be converted to the new type.
This program attempts to cast a reference to an array of type int[] and assign it to a reference variable of type double[]. Normally, a value of type int will be automatically converted to type double whenever there is a need for such a conversion. However, this attempted cast produces the following compiler error under JDK 1.3.
Ap074.java:19: inconvertible types
found : int[]
required: double[]
double[] B = (double[])A;
Why is this cast not allowed?
I can't give you a firm reason why such a cast is not allowed, but I believe that I have a good idea why. I speculate that this is due to the fact that the actual primitive values are physically stored in the array object, and primitive values of different types require different amounts of storage. For example, the type int requires 32 bits of storage while the type double requires 64 bits of storage.
Would require reconstructing the array object
Therefore, to convert an array object containing int values to an array object containing double values would require reconstructing the array object and allocating twice as much storage space for each element in the array.
Restriction doesn't apply to arrays of references
As you have seen from previous questions, such a casting restriction does not apply to arrays containing references to objects. This may be because the amount of storage required to store a reference to an object is the same, regardless of the type of the object. Therefore, the allowable casts that you have seen in the previous questions did not require any change to the size of the array. All that changed was some supplemental information regarding the type of objects to which the elements in the array refer.
A reference to an array can be assigned to a non-array
reference of the class named Object, as in the following statement
extracted from the program, where A is a reference to an array object
of type double.
Object B = A; |
Note that there are no square brackets anywhere in the above statement. Thus, the reference to the array object is not being assigned to an array reference of the type Object[]. Rather, it is being assigned to an ordinary reference variable of the type Object.
Downcasting to an array type
Once the array reference has been assigned to
the ordinary reference variable of the type Object, that reference
variable can be downcast and used to access the individual elements in
the array as illustrated in the following fragment. Note the square
brackets in the syntax of the cast operator: (double[]).
System.out.println( ((double[])B)[0] + " " + ((double[])B)[1]); |
Parentheses are critical
Note also that due to precedence issues, the placement
of both sets of parentheses is critical in the above code fragment.
You must downcast the reference variable before applying the index to that
variable.
The general rule for casting array references (for arrays whose declared type is the name of a class or an interface) is:
A reference to an array object can be cast to another array type if the elements of the referenced array are of a type that can be cast to the type of the elements of the specified array type.Old rules apply here also
Thus, the general rules covering conversion and casting up and down the inheritance hierarchy and among classes that implement the same interfaces also apply to the casting of references to array objects.
A reference to an object can be cast down the inheritance hierarchy to the actual class of the object. Therefore, an array reference can also be cast down the inheritance hierarchy to the declared class for the array object.
This program declares a reference to, creates,
and populates an array of the class type Subclass. This reference
is assigned to an array reference of a type that is a superclass of the
actual class type of the array. Then the superclass reference is
downcast to the actual class type of the array and assigned to a different
reference variable. This third reference variable is used to successfully
access and display the contents of the elements in the array.
While it is allowable to assign an array reference to an array reference variable declared for a class that is further up the inheritance hierarchy (as illustrated earlier), it is not allowable to cast an array reference down the inheritance hierarchy to a subclass of the original declared class for the array.
This program declares a reference for, creates, and populates a two-element array for a class named Superclass. Then it downcasts that reference to a subclass of the class named Superclass. The compiler is unable to determine that this is a problem. However, the runtime system throws the following exception, which terminates the program at runtime.
java.lang.ClassCastException: [LSuperclass;
at Worker.doArrays(Ap071.java:19)
at Ap071.main(Ap071.java:9)
This program illustrates that, if you have a reference to an array object containing references to other objects, you can assign the array object's reference to an array reference variable whose type is a superclass of the declared class of the array object. (As we will see later, this doesn't work for array objects containing primitive values.)
What can you do then?
Having made the assignment to the superclass reference variable, whether or not you can do anything useful with the elements in the array (without downcasting) depends on many factors.
No downcast required in this case
In this case, the ability to display the contents of the objects referred to in the array was inherited from the class named Superclass. Therefore, it is possible to access and display a String representation of the objects without downcasting the array object reference from Superclass to the actual type of the objects.
Probably need to downcast in most cases
However, that will often not be the case. In most cases, when using a reference of a superclass type, you will probably need to downcast in order to make effective use of the elements in the array object.
This is a straightforward application of Java array technology for the storage and retrieval of references to objects.
The program declares a reference to, creates, and populates a two-element array of a class named Subclass. The class named Subclass extends the class named Superclass, which in turn, extends the class named Object by default.
The super keyword
The class named Subclass doesn't do anything particularly useful other than to illustrate extending a class.
However, it also provides a preview of the use of the super keyword for the purpose of causing a constructor in a subclass to invoke a parameterized constructor in its superclass.
Setting the stage for future questions
The main purpose for showing you this program is to set the stage for several programs that will be using this class structure in subsequent questions.
There are some situations involving casting where the compiler cannot identify an erroneous condition that is later identified by the runtime system. This is one of those cases.
This program begins with an array of type double[]. The reference to that array is converted to type Object. Then it is cast to type String[]. All of these operations are allowed by the compiler.
However, at runtime, the runtime system expects to find references to objects of type String in the elements of the array. What it finds instead is values of type double stored in the elements of the array.
As a result, a ClassCastException is thrown. Since it isn't caught and handled by the program, the program terminates with the following error message showing on the screen.
java.lang.ClassCastException: [D
at Worker.doArrays(Ap068.java:17)
at Ap068.main(Ap068.java:6)
Finally, we managed to get it all together. The program compiles and executes correctly. This program illustrates the assignment of an array object's reference to a reference variable of type Object, and the casting of that reference of type Object back to the correct array type in order to gain access to the elements in the array.
But don't go away, there is a lot more that you need to know about arrays in Java. We will look at some of those things in the questions that follow.
While it is possible to store an array object's reference in a reference variable of type Object, and later cast it back to an array type to gain access to the elements in the array, you must use the correct syntax in performing the cast. This is not the correct syntax for performing that cast. It is missing the empty square brackets required to indicate a reference to an array object.
A portion of the compiler error produced by JDK 1.3 is shown below:
Ap066.java:17: inconvertible types
found : java.lang.Object
required: double
double C = (double)B;
This program illustrates another very important point. Although you can assign an array object's reference to a reference variable of type Object, you cannot gain access to the elements in the array while treating it as type Object. Rather, you must cast it back to an array type before you can gain access to the elements in the array object.
A portion of the compiler error produced by JDK 1.3 is shown below:
Ap065.java:18: array required, but java.lang.Object found
B[0] + " " + B[1]);
This program illustrates a very important point. You can assign an array object's reference to an ordinary reference variable of type Object. Note that I didn't say Object[]. The empty square brackets are not required when the type is Object.
Standard containers or collections
Later on, when we study the various containers in the Java class libraries (see the Java Collections Framework), we will see that they store references to all objects, including array objects, as type Object. Thus, if it were not possible to store a reference to an array object in a reference variable of type Object, it would not be possible to use the standard containers to store references to array objects.
Because it is possible to assign an array object's reference to a variable of type Object, it is also possible to store array object references in containers of type Object.
Richard has participated in numerous consulting projects involving Java, XML, or a combination of the two. He frequently provides onsite Java and/or XML training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Java Programming Tutorials, which has gained a worldwide following among experienced and aspiring Java programmers. He has also published articles on Java Programming in Java Pro magazine.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.
-end-