Полезная информация

Exploring Java

Previous: 6.4 Variable and Method VisibilityChapter 6
Relationships Between Classes
Next: 6.6 Inner Classes

6.5 Inside Arrays

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 an Animal[] array:

Figure 6.8: Arrays in the Java class hierarchy

Figure 6.8
Animal [][] animals; 
Bird [][] birds = new Bird [10][10]; 
birds[0][0] = new Bird(); 
// make animals and birds reference the same array object 
animals = birds;   
System.out.println( animals[0][0] );               // prints Bird 

Because arrays are part of the class hierarchy, we can use instanceof to check the type of an array:

if ( birds instanceof Animal[][] )                 // yes 

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();     // Run-time 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, as I described previously. 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.[4]

[4] 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 above.

Previous: 6.4 Variable and Method VisibilityExploring JavaNext: 6.6 Inner Classes
6.4 Variable and Method VisibilityBook Index6.6 Inner Classes

Other Books in this LibraryJava in a NutshellJava Language ReferenceJava AWTJava Fundamental ClassesExploring Java