I am trying to figure out why do I need Downcasting. I reread my notes from collage and found the below example.
class Student {...}
class Graduate exteds Student {
getResearchTopic(){...} // this method only exists in Graduate class.
}
We have a ref to Student class and want to access to getResearchTopic method;
Student s1 = new Graduate();
if(s1 instanceof Graduate){
((Graduate)s1).getResearchTopic();
}
Great example for Downcasting hah? My question is Why not declare s1 as a Graduate in the first place? Is there a real life example where I will have to downcast instead of using an instance of actual class?
Downcasting is useful when the type of the value referenced by the Parent variable is known and often is used when passing a value as a parameter. In the below example, the method objectToString takes an Object parameter which is assumed to be of type String.
Downcasting is another form of object type casting and is used in appointing the subclass reference object to the parent class that is not allowed in Java.
Downcasting is not allowed without an explicit type cast. The reason for this restriction is that the is-a relationship is not, in most of the cases, symmetric. A derived class could add new data members, and the class member functions that used these data members wouldn't apply to the base class.
Downcasting : Downcasting is to put the child class object reference ID back into child class object by using the parent class referene variable. Upcasting is required for downcasting. Main use of downcasting is that we can access child class method too from single object.
Well, you could have declared the reference s1
to be of type Graduate
. The main benefit you get by declaring the reference of super type
, is the power of polymorphism.
With a super type reference, pointing to a sub class object, you can bind the same reference to multiple sub class objects. And the actual method invoked will be decided at runtime, based on what object is being pointed to. But, the main condition for this is, that method should also be defined in the subclass, else the compiler will fail to find the method declaration.
Here, you were forced to downcast
, because you haven't defined the method in the super class. As compiler cannot see the definition of that method in Student
class. It has no idea about what the actual object s1
points to. Remember, compiler only checks the reference type to find the meethod declaration.
In general, whenever you see yourself downcasting to a subclass in your code, it is almost always a sign a something wrong (there are some exceptions though). And you should modify your classes.
Let's see what benefit you get by using a super class reference instead of a subclass reference:
For e.g: Suppose you have another sub class of Student
as:
class Phd extends Student {
getResearchTopic(){...}
}
and you also provide a definition (a default one) in Student
class:
class Student {
getResearchTopic(){...}
}
Now, you create a following two objects, both being pointed to by Student
reference:
Student student = new Phd();
student.getResearchTopic(); // Calls Phd class method
student = new Graduate();
student.getResearchTopic(); // Calls Graduate class method
So, with only a single reference, you get to access methods specific to subclasses.
One major implementation of this feature you can see in factory method
pattern, where a single static method returns an object of different sub classes based on some condition:
public static Student getInstance(String type) {
if (type.equals("graduate"))
return new Graduate();
else if (type.equals("phd"))
return new Phd();
}
So, you can see that the same method returns an object of different subclasses.
All of the above stuffs you can do just because of one concept:
A Super class reference can refer to any sub class objects, but not vice-versa.
Say you have a method that takes a Student
as a parameter. Most of the things it does are generic for all students. But if it is a Graduate
there might be something else it does as well. In that case you would need to determine if the Student
passed in was actually a Graduate
and do some special logic in that instance.
Maybe something like this:
class StudentDAO {
public void SaveStudent(Student s) {
// Do something to save the student data to a database.
if ( s instanceof Graduate ) {
// Save their research topic too.
}
}
}
Note that doing that kind of thing is usually a poor programming practice, but sometimes it makes sense.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With