Typecasting with Object References
Object references can be typecast only along a chain of inheritance. If class
MyDerived is derived from
MyBase, then a reference to
one can be typecast to the other.
An upcast converts from a derived type to a base type, and will be done implicitly,
because it is guaranteed that everything that could be used in the base is also in the derived class.
String s = new String("Hello");
o = s;
A downcast converts from a parent type to a derived type, and must be done explicitly.
Object o = new String("Hello");
t = (String) o;
o came from a
String, the compiler only
recognizes it as an
Object, since that is the type of data the variable is declared to hold.
As a memory aid, if you draw your inheritance diagrams with the parent class on top,
then an upcast moves up the page, while a downcast moves down the page.
More on Object Typecasts
The compiler will not check your downcasts, other than to confirm that the
cast is at least feasible. For instance, there is no possibility of a typecast between
Integer, since neither is a base class to the other.
But, the JVM will check at runtime to make sure that
the cast will succeed. A downcast could fail at runtime because you might call a method that is not there,
so the JVM checks when performing the cast in order to fail as soon as possible, rather
than possibly having some additional steps execute between casting and using a method.
Object o = new Integer(7);
String t, u;
// compiler will allow the following line, but it will fail at runtime
t = (String) o;
// we will never reach this line
u = t.toUpperCase();
t was not actually a
String, this would fail with a
runtime exception during the cast operation. At that point, the runtime engine sees that it
cannot make the conversion and fails.
You can use a typecast in the flow of an operation, such as:
MyBase rv = new MyDerived(2, 3);
"x=" + rv.getX() + " y=" + ((MyDerived) rv).getY() );
((MyBase) rv) casts
rv to a
MyDerived, for which
getY() method is run.
Note the parentheses enclosing the inline typecast operation; this is because
the dot operator is higher precedence than the typecast; without them
we would be trying to run
rv.getY() and typecast the result (technically, Java does not
consider the dot an operator, but a separator , like curly braces,
parentheses, and square brackets - the net effect is the same, since separators
get applied before operators).
Typecasting, Polymorphism, and Dynamic Method Invocation
The concept of polymorphism means "one thing - many forms."
In this case, the one thing is a base class variable; the many forms are the different types
derived from that base class that can be stored in the variable.
Storing a reference in a variable of a base type does not change the contents of the object,
just the compiler's identification of its type - it still has its original methods and fields.
You must explicitly downcast the references back to their original class
in order to access their unique properties and methods. If you have upcast, to store a derived class object with a base class reference, the compiler
will not recognize the existence of derived class methods that were not in the base class.
The collection classes, such as
Vector, are defined to store
so that anything you store in them loses its identity. You must downcast the reference back to the derived type in order to access those methods.
The introduction of generics provides a solution
to this annoyance (more on this in the Collections lesson).
During execution, using a base class reference to call to a method that has been
overridden in the derived class will result in the derived class version being used. This is called dynamic method invocation.
The following example prints the same way twice, even though two different types of
variables are used to reference the object:
Situations where you would often see a base class reference include:
- Parameters to methods that only need to work with base class elements
of the incoming object.
- As fields of a class where the class code will only work with the
base class elements of the object.
- Return values from methods where the actual class returned is not important
to the user, and you want to hide the actual class from the user - for
java.net.Socket object has a
getOutputStream() method that returns an instance of a specialized
class that will send data across the network connection that the
to use this class you only need to know that it is an
since there is no way you could use this class without the
is attached to.