Java Reference
In-Depth Information
Introduction to Generics
If we want to build a collection of
Shape
instances, we can use a
List
to hold them,
like this:
List
shapes
=
new
ArrayList
();
// Create a List to hold shapes
// Create some centered shapes, and store them in the list
shapes
.
add
(
new
CenteredCircle
(
1.0
,
1.0
,
1.0
));
// This is legal Java—but is a very bad design choice
shapes
.
add
(
new
CenteredSquare
(
2.5
,
2
,
3
));
// List::get() returns Object, so to get back a
// CenteredCircle we must cast
CenteredCircle
c
=
(
CentredCircle
)
shapes
.
get
(
0
);
// Next line causes a runtime failure
CenteredCircle
c
=
(
CentredCircle
)
shapes
.
get
(
1
);
A problem with this code stems from the requirement to perform a cast to get the
shape objects back out in a usable form—the
List
doesn't know what type of objects
it contains. Not only that, but it's actually possible to put different types of objects
into the same container—and everything will work fine until an illegal cast is used,
and the program crashes.
m
e
What we really want is a form of
List
that understands what type it contains. Then,
javac
could detect when an illegal argument was passed to the methods of
List
and
cause a compilation error, rather than deferring the issue to runtime.
Java provides syntax to cater for this—to indicate that a type is a container that
holds instances of another reference type we enclose the
payload
type that the con‐
tainer holds within angle brackets:
// Create a List-of-CenteredCircle
List
<
CenteredCircle
>
shapes
=
new
ArrayList
<
CenteredCircle
>();
// Create some centered shapes, and store them in the list
shapes
.
add
(
new
CenteredCircle
(
1.0
,
1.0
,
1.0
));
// Next line will cause a compilation error
shapes
.
add
(
new
CenteredSquare
(
2.5
,
2
,
3
));
// List<CenteredCircle>::get() returns a CenteredCircle, no cast needed
CenteredCircle
c
=
shapes
.
get
(
0
);
This syntax ensures that a large class of unsafe code is caught by the compiler,
before it gets anywhere near runtime. This is, of course, the whole point of static
type systems—to use compile-time knowledge to help eliminate whole swathes of
runtime problems.
Container types are usually called
generic types
—and they are declared like this: