Java Reference
In-Depth Information
Java automatically casts an object that belongs to a subclass to an object that
belongs to the superclass. The reverse is not true. However, an object that belongs
to the subclass can be explicitly cast to an object of type superclass. However, a
ClassCastException
will be raised if the super object variable does not actually
reference an object of the subclass type.
For example, even if the
FictionalCharacter
class was not abstract, the following line
will produce a compilation error.
Superhero s = (Superhero)
new
FictionalCharacter () ;
The reason is that
s
references an object of type
FictionalCharacter
and therefore
s
does not support variables such as
goodPower
. However, the syntax
Superhero s
implies
that the
s
object must have the variables
goodPower
and
respect
associated with it.
The second
magical
feature of our program is that the correct
toString
method is
executed for every fictional character of the
ArrayList
. Here is what happened. When
Java sees the syntax
element.toString()
, it determines the object that
element
refers
to. If
element
refers to an object of type
Superhero
, then the
toString
method from the
Superhero
class is executed. Otherwise, if
element
refers to an object of type
Villain
,
then the
toString
method from the
Villain
class is executed. This magical property of
always finding the right method to execute is called
polymorphism
. This term was chosen
because the
toString
method takes many forms and the correct version is always executed.
When the Java compiler sees the syntax
o.m(
...
)
,where
o
is an object variable
and
m
is an instance method, the type of the
o
object is ignored. Java only considers
the object which
o
references. Suppose that this object belongs to the
C
class. If the
C
class contains the
m
method with the correct parameters, then the method is executed.
Otherwise, Java searches in the superclass of the
C
class for the
m
method. The search
continues until Java reaches the root or inheritance hierarchy (more on this later).
Note that if neither the
C
class nor one of its ancestors contains the
m
method, then
the code
o.m(
...
)
will not compile. The reason is that the
C
class must be either
the class to which the
o
object belongs or one of its descendants in the inheritance
hierarchy.
Let us examine the following code from the
main
method.
for
(FictionalCharacter character : characters)
{
System.out. println(character . toString()) ;
}
We did not need to add the call to the method
toString
(it is automatically called
for the method
println
), but we did so in order to make the example clearer. The vari-
able
characters
is an
ArrayList
of objects of type
FictionalCharacter
.Thevariable
character
iterates over the elements of the
ArrayList
. Even though the type of the vari-
able
character
is
FictionalCharacter
, Java disregards this type when it tries to find
the correct method to execute. If the
character
object references a superhero, then the
toString
method from the
Superhero
class is executed. Alternatively, if the
character
ob-
ject references a villain, then the
toString
method from the
Villain
class is executed. Note
that in order for the code to compile, the
FictionalCharacter
class or one of its super-
classes (or, in general, ancestors in the inheritance heterarchy) must contain the
toString
method. However, this is not necessarily the
toString
method that will be executed.