Java Reference
In-Depth Information
printArray
generic method with the additional parameters
lowSubscript
and
highSub-
script
to specify the portion of the array to output (see Exercise 20.5).
A generic method can also be overloaded by nongeneric methods. When the compiler
encounters a method call, it searches for the method declaration that best matches the
method name and the argument types specified in the call—an error occurs if two or more
overloaded methods both could be considered best matches. For example, generic method
printArray
of Fig. 20.3 could be overloaded with a version that's specific to
String
s,
which outputs the
String
s in neat, tabular format (see Exercise 20.6).
The concept of a data structure, such as a stack, can be understood
independently
of the el-
ement type it manipulates. Generic classes provide a means for describing the concept of a
stack (or any other class) in a
type-independent
manner. We can then instantiate
type-specific
objects of the generic class. Generics provide a nice opportunity for software reusability.
Once you have a generic class, you can use a simple, concise notation to indicate the
type(s) that should be used in place of the class's type parameter(s). At compilation time,
the compiler ensures the
type safety
of your code and uses the
erasure
techniques described
in Sections 20.3-20.4 to enable your client code to interact with the generic class.
One generic
Stack
class, for example, could be the basis for creating many logical
Stack
classes (e.g., “
Stack
of
Double
,” “
Stack
of
Integer
,” “
Stack
of
Character
,” “
Stack
of
Employee
”). These classes are known as
parameterized classes
or
parameterized types
because they accept one or more type parameters. Recall that type parameters represent
only
reference types
, which means the
Stack
generic class cannot be instantiated with prim-
itive types. However, we can instantiate a
Stack
that stores objects of Java's type-wrapper
classes and allow Java to use
autoboxing
to convert the primitive values into objects. Recall
that autoboxing occurs when a value of a primitive type (e.g.,
int
) is pushed onto a
Stack
that contains wrapper-class objects (e.g.,
Integer
).
Auto-unboxing
occurs when an object
of the wrapper class is popped off the
Stack
and assigned to a primitive-type variable.
Implementing a Generic
Stack
Class
Figure 20.7 declares a generic
Stack
class for demonstration purposes—the
java.util
package already contains a generic
Stack
class. A generic class declaration looks like a non-
generic one, but the class name is followed by
a type-parameter section
(line 5). In this case,
type parameter
T
represents the element type the
Stack
will manipulate. As with generic
methods, the type-parameter section of a generic class can have one or more type param-
eters separated by commas. (You'll create a generic class with two type parameters in
Exercise 20.8.) Type parameter
T
is used throughout the
Stack
class declaration to repre-
sent the element type. This example implements a
Stack
as an
ArrayList
.
Class
Stack
declares variable
elements
as an
ArrayList<T>
(line 7). This
ArrayList
will store the
Stack
's elements. As you know, an
ArrayList
can grow dynamically, so
objects of our
Stack
class can also grow dynamically. The
Stack
class's no-argument con-
structor (lines 10-13) invokes the one-argument constructor (lines 16-20) to create a
Stack
in which the underlying
ArrayList
has a capacity of
10
elements. The one-argu-
ment constructor can also be called directly to create a
Stack
with a specified initial
capacity. Line 18 validates the constructor's argument. Line 19 creates the
ArrayList
of
the specified capacity (or 10 if the capacity was invalid).