At the end of Chapter 4, we mentioned that arrays have a place in the Java class hierarchy, but we didn’t give you any details. Now that we’ve discussed the object-oriented aspects of Java, we can give you the whole story.
Array classes live in a parallel Java class hierarchy under the
Object
class. If a class is a direct subclass of Object
,
then an array class for that base type also exists as a direct
subclass of Object
. Arrays of more derived classes
are subclasses of the corresponding array classes. For example,
consider the following class types:
class Animal { ... } class Bird extends Animal { ... } class Penguin extends Bird { ... }
Figure 6.8 illustrates the class hierarchy for
arrays of these classes. Arrays of the same dimension are related to
one another in the same manner as their base type classes. In our
example, Bird
is a subclass of
Animal
, which means that the
Bird[]
type is a subtype of
Animal[]
. In the same way a
Bird
object can be used in place of an
Animal
object, a Bird[]
array
can be assigned to a variable of type Animal[]
:
Animal [][] animals; Bird [][] birds = new Bird [10][10]; birds[0][0] = new Bird( ); // make animals and birds reference the same array object animals = birds; Observe( animals[0][0] ); // processes Bird object
Because arrays are part of the class hierarchy, we can use
instanceof
to check the type of an array:
if ( birds instanceof Animal[][] ) // true
An array is a subtype of Object
and can therefore
be assigned to Object
type variables:
Object something; something = animals;
Since Java knows the actual type of all objects, you can also cast back if appropriate:
animals = (Animal [][])something;
Under
unusual circumstances, Java may not be able to check the types of
objects you place into arrays at compile time. In those cases,
it’s possible to receive an
ArrayStoreException
if you try to assign the wrong
type of object to an array element. Consider the following:
class Dog { ... } class Poodle extends Dog { ... } class Chihuahua extends Dog { ... } Dog [] dogs; Poodle [] poodles = new Poodle [10]; dogs = poodles; dogs[3] = new Chihuahua( ); // runtime error, ArrayStoreException
Both Poodle
and Chihuahua
are
subclasses of Dog
, so an array of
Poodle
objects can therefore be assigned to an
array of Dog
objects. The problem is that an
object assignable to an element of an array of type
Dog[]
may not be assignable to an element of an
array of type Poodle[]
. A
Chihuahua
object, for instance, can be assigned to
a Dog
element because it’s a subtype of
Dog
, but not to
a Poodle
element.[22]
[22] In some sense, this could be considered a hole in the Java type system. It doesn’t occur elsewhere in Java—only with arrays. This is because array objects exhibit covariance in overriding their assignment and extraction methods. Covariance allows array subclasses to override methods with arguments or return values that are subtypes of the overridden methods, where the methods would normally be overloaded or prohibited. This allows array subclasses to operate on their base types with type safety, but also means that subclasses have different capabilities than their parents, leading to the problem shown earlier.
Get Learning Java now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.