A Quick Tutorial on Casting

Recently, I’ve been teaching a class and one of the students stopped by after the class and said, “I’m just learning object-oriented programming, can you explain me the benefits of casting?”. How would you answer such a question? I did my best in a short period of time I had, but felt obligated to give better explanations and wrote this blog. I’ve been using example from Java language here, but all this apply to other object-oriented languages too.

All Java classes form an inheritance tree with the class Object on top of the hierarchy – all Java classes are direct or indirect descendants of Object. When you declare a non-primitive variable, you are allowed to use either the exact data type of this variable or one of its ancestor data types. For example, if the class NJTax extends Tax each of the following lines is correct.

NJTax myTax1 = new NJTax();
Tax myTax2 = new NJTax(); // upcasting
Object myTax3 = new NJTax(); // upcasting

Java is smart enough to automatically cast an instance of the class to its ancestor. When the variable has more generic class than an instance of the object it’s called upcasting. Let’s say the class object has ten methods and class variables defined, the class Tax (it’s an implicit subclass of Object) adds five more methods and variables (total 15), and NJTax adds another two (total 17). The variable myTax1 will have access to all 17 methods and variables, myTax2 will see only 15, and myTax3 just 10. Why not always use exact types in variable declarations?

Let’s say you need to write a program that will process the data about workers of a certain company. Some of them are full time employees, and some are contractors, but you’d like to read them from some data source and into the same array. Arrays can store only the objects of the same type, remember?

Since Java can automatically upcast the objects, you can create a class Person with two subclasses: Employee and Contractor, and then read the records from a database, and based on the employment type, create an appropriate object instance and put it into an array of type Person:

Person workers[] = new Person [100];
workers[0] = new Employee(“Yakov”, “Fain”);
workers[1] = new Employee(“Mary”, “Lou”);
workers[2] = new Contractor(“Bill”, “Shaw”);

Of course, you could’ve created two separate arrays for employees and contractors, but I’m laying the foundation here for explaining polymorphism – a powerful concept of object-oriented languages.

At some point you’ll need to process the data from the array workers. Say, in a loop you can test the data type of the current element of the array with the operator instanceOf, then downcast the object (it can’t be done automatically) to Employee or Contractor, and process it accordingly.

for (int i; i<20; i++){
Employee currentEmployee;
Contractor currentContractor;

if (worksers[i] instanceof Employee){
currentEmployee = (Employee) workers[i];
// do some employee processing here
} else if (worksers[i] instanceof Contractor){
currentContractor = (Contractor) workers[i];
// do some contractor processing here
}
}

Placing a data type in parenthesis in front of another object means that you want to downcast this object to specified type. You can downcast an object only to one of its descendant data types. Even though the above code has correct syntax, it doesn’t represent the best practice of processing similar objects. In the next lesson you’ll see how to use polymorphism to do it in a more generic way.
If a class implements an interface, you can cast it to this interface. Say, a class Employee implements Payable, Insurable, Pensionable interfaces:

class Employee implements Payable, Insurable, and Pensionable {
// implementation of all interfaces goes here
}

If in particular code you are interested in its Insurable behavior, there’s not need to cast the Object to type Employee, just cast it to Insurable type as shown in the code fragment below. Keep in mind though that if you do so, the variable current employee will expose the access to only those methods that were declared in the Insurable interface.

Insurable currentEmployee;

if (worksers[i] instanceof Employee Insurable){
currentEmployee = (Insurable) workers[i];
// do some insurance-specific processing here
}

Is it clear enough? I’d appreciate your feedback.

Yakov Fain