Java Reference
In-Depth Information
The reason for this is simple—we don't know what the payload type of
mysteryList
is! For example, if
mysteryList
was really a instance of
ArrayList<String>
, then
we wouldn't expect to be able to put an
Object
into it.
The only value that we know we can always insert into a container is
null
—as we
know that null is a possible value for any reference type. This isn't that useful, and
for this reason, the Java language spec also rules out instantiating a container object
with the unknown type as payload, for example:
// Won't compile
List
<?>
unknowns
=
new
ArrayList
<?>();
A very important use for the unknown type stems from the question, “Is
List<String>
a subtype of
List<Object>
?” That is, can we write this?
// Is this legal?
List
<
Object
>
objects
=
new
ArrayList
<
String
>();
At first glance, this seems entirely reasonable—
String
is a subclass of
Object
, so we
know that any
String
element in our collection is also a valid
Object
. However,
consider the following code:
m
e
// Is this legal?
List
<
Object
>
objects
=
new
ArrayList
<
String
>();
// If so, what do we do about this?
objects
.
add
(
new
Object
());
As the type of
objects
was declared to be
List<Object>
, then it should be legal to
add an
Object
instance to it. However, as the actual instance holds strings, then try‐
ing to add an
Object
would not be compatible, and so this would fail at runtime.
The resolution for this is to realize that although this is legal (because
String
inher‐
its from
Object
):
Object
o
=
new
String
(
"X"
);
that does not mean that the corresponding statement for generic container types is
also true:
// Won't compile
List
<
Object
>
objects
=
new
ArrayList
<
String
>();
Another way of saying this is that
List<String>
is
not
a subtype of
List<Object>
.
If we want to have a subtyping relationship for containers, then we need to use the
unknown type:
// Perfectly legal
List
<?>
objects
=
new
ArrayList
<
String
>();
This means that
List<String>
is
a subtype of
List<?>
—although when we use an
assignment like the preceding one, we have lost some type information. For exam‐
ple, the return type of
get()
is now effectively
Object
. You should also note that
List<?>
is not a subtype of any
List<T>
, for any value of
T
.