class Parent{ /* ... */}class ChildClass extends Parent { /* ... */ }public class Tester { public static void main (String args[ ]) { Parent p = new Parent ( ); /*this is a downcast since the Parent class object, "p" is being cast to a ChildClass type, and ChildClass derives from the Parent class */ ChildClass c = (ChildClass) p; }}
1. It will compile and run without any errors2. It will throw a compile time exception3. It will throw a Runtime exception
It helps to first define exactly what a downcast is. It’s actually pretty simple – suppose you have a base class, and a class that derives from that base class either directly or indirectly. Then, anytime an object of that base class type is type cast into a derived class type, it is called a downcast. The reason it’s called a downcast is because of the way that inheritance diagrams are normally written – base classes are at the top and derived classes are down below the base classes. So, in downcasting, you are going down the inheritance diagram by taking an object of a base class (at the top), and thentrying to convert into the type of one of the derived classes (going down). The key word there istrying – because downcasting does not always make sense depending on the code being written. In the code above, this line is where the downcast is being performed:
ChildClass c = (ChildClass) p;
The code above will actually compile, but at runtime it will throw a Runtime Exception (a java.lang.ClassCastException).
If a Java expert would look at the code in our example up above, he or she would definitely know that the code would not work at run-time. So, why does it even compile? Well, remember that the compiler sees things differently from humans – and it thinks that the programmer knows what he is doing. But, in any case, the error is found at run time. By having the cast there (remember the cast is the “(ChildClass) p”), we are telling the compiler that we really do actually want to do this – it is not just a mistake in typing. So, the compiler trusts our judgement. But at runtime Java finds out that the object “p” is of the “ParentClass” type, and it will throw a Runtime Exception.
Suppose there is no type cast, and the critical line of code above is changed so that it looks like this:
ChildClass c = p;
Then this code would give acompile time error instead of a runtime error – because there is no way that an object of the Parent class can ever be downcast to an object of it’s child class.
Yes, downcasting is allowed in Java – if it wasn’t then the code up above would always return an error at compile time, not just at run-time. So, you might be wondering when exactly would it make sense to do a downcast – and that is a very good question. Downcasting is very useful when you need to compare one object to another. An example would help clarify – take a look at the code below:
public class Person{ private String name; private int age; public boolean equals(Object anObject) { if (anObject == null) return false; /* The object being passed in is checked to see it's class type which is then compared to the class type of the current class. If they are not equal then it returns false */ else if (getClass( ) != anObject.getClass()) return false; else { /* this is a downcast since the Object class is always at the very top of the inheritance tree and all classes derive either directly or indirectly from Object: */ Person aPerson = (Person) anObject; return ( name.equals(aPerson.name) && (age == aPerson.age)); } }}
In the equals( ) method above, you can see that a downcast is being performed. The equals method is just comparing 2 objects to see if the name and age are equal in both objects. If so, it returns true. In the example above we have a Person class. Let’s also suppose that we also have some other classes that inherit or derive from the Person class – like AsianPerson, AmericanPerson, EuropePerson, etc. And, if we wanted to compare those classes to each other, then we would need an equals method like the one shown above. This method just accepts an object of type Object – because it needs to be able to accept any type of object.
Remember that in Java, every descendant of a class X is also of type X. This means that every descendant of the Person class is also of type Person. This is why downcasting would work if, in the equals method above, any object of a class type that is descended from Person is passed to the method. So, the equals method above is a great example of when downcasting is necessary and helpful – because it allows us to compare objects that are related via a common ancestor.
You can see that in the code above we run this:
else if (getClass( ) != anObject.getClass()) return false;
The getClass() method allows us to get the class of the object being passed in and compare it to the class of the current class. If they are not equal then we don’t want to bother comparing them, and we know that the downcasting would be pointless.
Would you like to thankProgrammerInterview.com for being a helpful free resource?Then why not tell a friend about us, orsimply add a link to this page from your webpage using the HTML below.
Link to this page:
Please bookmark with social media, your votes are noticed and appreciated: