Published: January 1, 2004
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: Interfaces and polymorphic behavior.
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 Ap141{ |
2. What output is produced by the following program?
public class Ap142{ |
3. What output is produced by the following program?
public class Ap143{ |
4. What output is produced by the following program?
public class Ap144{ |
5. What output is produced by the following program?
import java.util.ArrayList; |
6. What output is produced by the following program?
import java.util.ArrayList; |
7. What output is produced by the following program?
public class Ap147{ |
8. What output is produced by the following program?
public class Ap148{ |
9. What output is produced by the following program?
public class Ap149{ |
10. What output is produced by the following program?
public class Ap150{ |
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.
C. AB CD EF
B. Runtime Error
This is another example of a program that throws an index out of bounds exception. In this case, since the container is an array object, the name of the exception is ArrayIndexOutOfBoundsException.
Populate a three-element array object
The code in the following fragment creates and
populates a three-element array object containing reference to three String
objects.
void doIt(){ |
Access an out-of-bounds element
The next fragment attempts to access an
element
in the array at index value 3.
for(int i = 0; i <= 3; i++){ |
Since index value 3 is outside the bounds of the array, the program throws the following exception and aborts:
AB CD EF
java.lang.ArrayIndexOutOfBoundsException
at
Worker.doIt(Ap150.java:22)
at
Ap150.main(Ap150.java:14)
Note however that the program displays the contents of the three String objects referred to by the contents of the first three elements in the array before the problem occurs. That's the way it often is with runtime errors. Often, a program will partially complete its task before getting into trouble and aborting with a runtime error.
If you feel like you've been had, chances are you have been had. The only purpose for Question 8 was to set you up for this question.
Division by zero for integer types
This program deals with the process of
dividing
by zero for int types. The code in the following fragment
divides the int value 1 by the int value 0.
void doIt(){ |
Not the same as double divide by zero
However, unlike with type double, this process doesn't return a very large value and continue running. Rather, for type int, attempting to divide by zero will result in a runtime error of type ArithmeticException that looks something like the following under JDK 1.3:
java.lang.ArithmeticException: / by zero
at Worker.doIt(Ap149.java:20)
at Ap149.main(Ap149.java:14)
An exercise for the student
I won't attempt to explain the difference in behavior for essentially the same problem between type int and type double. As the old saying goes, I'll leave that as an exercise for the student.
This program deals with the process of dividing by zero for floating values of type double.
The following code fragment attempts to divide
the double value 1.0 by the double value 0.
void doIt(){ |
The program runs successfully, producing the output Infinity.
What is Infinity?
Suffice it to say that Infinity is a very large number.
(Any value divided by zero is a very large number.)At this point, I'm not going to explain it further. If you are interested in learning what you can do with infinity, see the language specifications.
Instantiate and populate an ArrayList object
By now, you will be familiar with the kind of container object that you get when you instantiate the ArrayList class.
The code in the following fragment instantiates such a container, having an initial capacity of one element.
Then it adds two elements to the container. Each element is a
reference to an object of the class String.
void doIt(){ |
Increase capacity automatically
Because two elements were successfully added to a container having an initial capacity of only one element, the container was forced to increase its capacity automatically.
Following execution of the code in the above fragment, String object references were stored at index locations 0 and 1 in the ArrayList object.
Get reference at index location 2
The next fragment attempts to use the get() method to fetch an element from the container at index value 2.
Index values in an ArrayList object begin with zero.
Therefore,
since only two elements were added to the container in the earlier
fragment,
there
is no element at index value 2.
|
An IndexOutOfBounds exception
As a result, the program throws an IndexOutOfBounds exception. The error produced under JDK 1.3 looks something like the following:
Exception in thread "main"
java.lang.IndexOutOfBoundsException:
Index: 2, Size: 2
at java.util.ArrayList.RangeCheck
(Unknown Source)
at java.util.ArrayList.get
(Unknown Source)
at Worker.doIt(Ap147.java:27)
at Ap147.main(Ap147.java:16)
Attempting to access an element with a negative index value would produce the same result.
An ArrayIndexOutOfBounds exception
A similar result occurs if you attempt to access an element in an ordinary array object outside the bounds of the index values determined by the size of the array. However, in that case, the name of the exception is ArrayIndexOutOfBounds.
Interestingly, one of the first things that you read when you start reading Java books, is that there are no pointers in Java. It is likely that shortly thereafter when you begin writing, compiling, and executing simple Java programs, one of your programs will abort with an error message looking something like that shown below:
Exception in thread "main" java.lang.NullPointerException
at Worker.doIt(Ap146.java:23)
at Ap146.main(Ap146.java:16)
What is a NullPointerException?
Stated simply, a NullPointerException occurs when you attempt to perform some operation on an object using a reference that doesn't refer to an object.
That is the case in this program
The following code fragment declares a local reference variable and initializes its value to null.
(A reference variable in Java must either refer to a valid object, or specifically refer to no object (null). Unlike a pointer in C and C++, a Java reference variable cannot refer to something arbitrary.)In this case, null means that the reference variable doesn't refer to a valid object.
void doIt(){ |
No ArrayList object
Note that the code in the above fragment does not instantiate an object of the class ArrayList and assign that object's reference to the reference variable.
(The reference variable doesn't contain a reference to an object instantiated from the class named ArrayList, or an object instantiated from any class for that matter.)Invoke a method on the reference
However, the code in the next fragment
attempts
to add a String object's reference to a nonexistent ArrayList
object by invoking the add method on the reference containing null.
ref.add("ABC "); |
This results in the NullPointerException shown earlier.
What can you do with a null reference?
The only operation that you can perform on a reference variable containing null is to assign an object's reference to the variable. Any other attempted operation will result in a NullPointerException.
This program is the same as the program in Question 4 with a major
exception.
Specifically, the program contains the import directive shown
in
the following fragment.
import java.util.ArrayList; |
A shortcut
The designers of Java recognized that having to type a fully-qualified name for every reference to a class in a Java program can become burdensome. Therefore, they provided us with a shortcut that can be used, so long as we don't need to refer to two or more class files having the same name.
Import directives
The shortcut is called an import directive.
As can be seen above, the import directive consists of the word import followed by the fully-qualified name of a class file that will be used in the program.
A program may have more than one import directive, with each import directive specifying the location of a different class file.
The import directive(s) must appear before any class or interface definitions in the source code.
The alternative wild-card syntax
An alternative form of the import directive replaces the name of the class with an asterisk.
The asterisk behaves as a wild-card character. It tells the compiler to use any class file that it finds in that package that matches a class reference in the source code.
The wild-card form should be used with care, because it can sometimes cause the compiler to use a class file that is different from the one that you intended to use (if it finds the wrong one first).
Class file name collisions
If your source code refers to two different class files having the same name, you must forego the use of the import directive and provide fully-qualified names for those class files.
No fully-qualified class names
This program is the same as the program in Question 3 with a major
exception.
Neither of the references to the ArrayList class use
fully-qualified
names in this program. Rather, the references are as shown in the
following fragment.
ArrayList ref = |
Compiler errors
As a result, the JDK 1.3 compiler produces two error messages similar to the following:
Ap144.java:20: cannot resolve symbol
symbol : class ArrayList
location: class Worker
ArrayList ref =
Doesn't know how to find the class file
This error message indicates that the compiler didn't know where to look on the disk to find the file named ArrayList.class
Since it was necessary to make use of a class to illustrate packages, this program also previews the use of the ArrayList class. We will be very interested in this class later when we study Java data containers.
What is an ArrayList object?
Some of this terminology may not make much sense to you at this point, but I'll go ahead and tell you anyway, just as a preview.
According to Sun, the ArrayList class provides a
"Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)"Stated more simply ...
Stated more simply, an object of the ArrayList class can be used as a replacement for an array object. An ArrayList object knows how to increase its capacity on demand, whereas the capacity of a simple array object cannon change once it is instantiated.
An ArrayList object
The following statement instantiates a new object of the ArrayList
class, with an initial capacity for one element. The initial
capacity
is determined by the int value passed to the constructor when
the
object is instantiated.
java.util.ArrayList ref = |
Back to the primary purpose ...
Getting back to the primary purpose of this program, what is the meaning of the term java.util that appears ahead of the name of the class, ArrayList?
Avoiding name conflicts
One of the age-old problems in computer programming has to do with the potential for name conflicts. The advent of OOP and reusable code didn't cause that problem to go away. If anything, it made the problem worse.
For example, you and I may work as programmers for separate companies named X and Y. A company named Z may purchase our two companies and attempt to merge the software that we have written separately. Given that there are only a finite number of meaningful class names, there is a good possibility that you and I may have defined different classes with the same names. Furthermore, it may prove useful to use both of the class definitions in a new program.
Put class files in different directories
Sun's solution to the problem is to cause compiled class files to reside in different directories. Simplifying things somewhat, if your compiled file for a class named Joe is placed in a directory named X, and my compiled file for a different class named Joe is placed in a directory named Y, then source code in the same Java program can refer to those two class files as X.Joe and Y.Joe. This scheme makes it possible for the Java compiler and the Java virtual machine to distinguish between the two files having the name Joe.class.
The java and util directories
Again, simplifying things slightly, the code in the above fragment refers to a file named ArrayList.class, which is stored in a directory named util, which is a subdirectory of a directory named java.
The directory named java is the root of a directory tree containing a very large number of standard Java class files.
(As an aside, there is another directory named javax, which forms the root of another directory tree containing class files considered to be extensions to the standard class library.)Many directories (packages)
Stated simply, a Java package is nothing more or less than a directory containing class files.
The standard and extended Java class libraries are scattered among a fairly large number of directories or packages (a quick count of the packages in the JDK 1.3 documentation indicates that there are approximately 65 standard and extended packages).
A fully-qualified class name
With one exception, whenever you refer to a class in a Java program, you must provide a fully-qualified name for the class, including the path through the directory tree culminating in the name of the class. Thus, the following is the fully-qualified name for the class whose name is ArrayList.
java.util.ArrayList
(Later we will see another way to accomplish this that requires less typing effort.)
The exception
The one exception to the rule is the use of classes in the java.lang package, (such as Boolean, Class, and Double). Your source code can refer to classes in the java.lang package without the requirement to provide a fully-qualified class name.
An ArrayList object
Now back to the use of the object previously instantiated from the class named ArrayList. This is the kind of object that is often referred to as a container.
(A container in this sense is an object that is used to store references to other objects.)Many methods available
An object of the ArrayList class provides a variety of methods that can be used to store object references and to fetch the references that it contains.
The add() method
One of those methods is the method named add().
The following code fragment instantiates three objects of the String class, and stores them in the ArrayList object instantiated earlier.
(Note that since the initial capacity of the ArrayList object was adequate to store only a single reference, the following code causes the object to automatically increase its capacity to at least three.)
ref.add("ABC "); |
The get() method
The references stored in an object of the ArrayList class can be fetched by invoking the get(int value) method on a reference to the object.
The code in the following fragment invokes this method to fetch the
references stored in index locations 0, 1, and 2. These
references
are passed to the println() method, where the contents of the String
objects referred to by those references are concatenated and displayed
on the computer screen.
System.out.println( |
The output
This results in the following being displayed:
ABC DEF GHI
Summary
The above discussion gave you a preview into the use of containers in general, and the ArrayList container in particular.
However, the primary purpose of this program was to help you to understand the use of packages in Java.
The ArrayList class was simply used as an example of a class file that is stored in a standard Java package.
As in Question 1, the program instantiates two String
objects
containing identical character strings, as shown in the following code
fragment.
char[] anArray = {'J','o','e'}; |
Compare objects for equality
Also, as in Question 1, this program compares the two objects for
equality
and displays the result as shown by the boldface portion of the
statement
in the following fragment.
System.out.println( |
Compare using overridden equals() method
However, in this program, the == operator is not used to compare the two objects. Rather, the objects are compared using an overridden version of the equals() method. In this case, the equals() method returns true, indicating that the objects are of the same type and contain the same data values.
The equals() method
The equals() method is defined in the Object class, and can be overridden in subclasses of Object. It is the responsibility of the author of the subclass to override the method so as to implement that author's concept of "equal" insofar as objects of the class are concerned.
The overridden equals() method
The reason that the equals() method returned true in this case was that the author of the String class provided an overridden version of the equals() method.
The default equals() method
If the author of the class does not override the equals() method, and the default version of the equals() method inherited from Object is invoked on an object of the class, then according to Sun:
"for any reference values x and y, this method returns true if and only if x and y refer to the same object (x==y has the value true)"In other words, the default version of the equals() method inherited from the class Object provides the same behavior as the == operator when applied to object references.
This program illustrates the behavior of the == operator (referred to as identity in some College Board documents) when used to compare references to objects.
Two String objects with identical contents
As shown in the following fragment, this program instantiates two
objects
of the String class containing identical character strings.
class Worker{ |
The fact that the two String object contain identical character strings is confirmed by:
The references to the two String objects are compared using
the
==
operator, and the result of that comparison is displayed. This
comparison
will produce either true or false. The code to
accomplish
this comparison is shown in the boldface portion of the following
fragment.
System.out.println( |
The statement in the above fragment produces the following display:
Joe Joe false
How can this be false?
We know that the two objects are of the same type (String) and that they contain the same character strings. Why does the == operator return false?
Doesn't compare the objects
The answer lies in the fact that the above statement doesn't really compare the two objects at all. Rather, it compares the values stored in the reference variables referring to the two objects. That is not the same as comparing the objects.
References are not equal
Even though the objects are of the same type and contain the same character string, they are two different objects, located in different parts of memory. Therefore, the contents of the two reference variables containing references to the two objects are not equal.
The correct answer is false
The == operator returns false as it should. The only way that the == operator could return true is if both reference variables refer to the same object, (which is not the case).
The bottom line is ...
The == operator cannot be used to compare two objects for equality. However, it can be used to determine if two reference variables refer to the same 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-