Typecasting with Object References

Contact Us or call 1-877-932-8228
Typecasting with Object References

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.

Object o;
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");
String t;
t = (String) o;

even though 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 typecase between String and 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();

Since 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 the 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 Objects, 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 in Java 1.5 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 variable are used to reference the object:

Code Sample:

public class Inheritance3 {
  public static void main(String[] args) {
    MyDerived mD = new MyDerived(2, 3);
    MyBase mB = mD;

Situations where you would often see a base class reference:

  • 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 example, a java.net.Socket object has a public OutputStream getOutputStream () method that returns an instance of a specialized class that will send data across the network connection that the Socket holds; to use this class you only need to know that it is an OutputStream, since there is no way you could use this class without the Socket it is attached to.