Why do we need downcasting really?

I am trying to understand why I need Downcasting. I reread my notes from the collage and found the example below.

class Student {...} class Graduate exteds Student { getResearchTopic(){...} // this method only exists in Graduate class. } 

We have a reference to the Student class and you want to access the 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 when I have to dump, instead of using an instance of the actual class?

+4
source share
5 answers

Well, you could specify a s1 link of type Graduate . The main advantage you get when declaring a super type link is the power of polymorphism.

With a reference to a supertype pointing to a subclass object, you can bind the same link to several objects of the subclass. And the actual method invoked will be determined at runtime, based on which object they point to. But the main condition for this is that this method must also be defined in a subclass, otherwise the compiler will not be able to find the method declaration.

Here you were forced downcast because you did not define a method in the superclass. Because the compiler cannot determine the definition of this method in the Student class. He has no idea what the actual object s1 points to. Remember that the compiler checks the type of link to find a meethod declaration.

In general, whenever you see that you are suppressing a subclass in your code, it is almost always a sign of something wrong (there are exceptions). And you have to change your classes.


See how you will benefit by using a superclass link instead of a subclass link:

For example, suppose you have another subclass of the Student class like:

 class Phd extends Student { getResearchTopic(){...} } 

and you also provide a definition (default) in the Student class:

 class Student { getResearchTopic(){...} } 

Now you create the following two objects that the Student link points to:

 Student student = new Phd(); student.getResearchTopic(); // Calls Phd class method student = new Graduate(); student.getResearchTopic(); // Calls Graduate class method 

So, with just one link, you get access to subclass-specific methods.


You can see one of the main implementations of this function in the factory method template, where one static method returns an object of different subclasses 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 from different subclasses.

All the things listed above can be done only according to one concept:

A reference to a superclass can refer to any objects of a subclass, but not vice versa.

+3
source

Say you have a method that takes a Student parameter as a parameter. Most of the things he does are common to all students. But if it's Graduate , maybe something else it does. In this case, you will need to determine if the passed Student actually a Graduate and make some special logic in this case.

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 this kind of thing is usually bad programming practice, but sometimes it makes sense.

+6
source

In those cases when you want to use polymorphism, it would be nice to work with Student objects, and then use downgrade methods specific to Graduate objects.

In general, if you have a method that works with Student objects, this method does not know at compile time which specific type of Student object is passed. Thus, at run time, the method should check the specific type and process accordingly.

0
source

Downcasting helps when you try to create common methods. For example, I often see code that parses an XML String in an Object . Object can then be omitted into a specific Object that you (as an encoder) know what it represents.

 private static XStream xstream = new XStream(new DomDriver()); static { xstream.processAnnotations(MyFirstClass.class); xstream.processAnnotations(MySecondClass.class); // ... } public static Object fromXML(String xml) { return xstream.fromXML(xml); } 

This allows me to make a very general method that does what I want it to do in all cases. Then, when I call it, I can simply omit Object into what I know will be. This prevents me from making a separate parsing method for each type of object and improves the readability of my code.

 MyFirstClass parsedObject = (MyFirstClass) MyXMLTransformer.fromXML(xml); 
0
source

When deserializing an object using the Java deserializer, you use this code by default (and use the same code when using another deserializer, such as the Jackson JSON deserializer)

 ObjectInputStream ois = new ObjectInputStream(in); Object obj = ois.readObject(); 

Then you need to apply obj to its actual type, because readObject() will always return a plain old Object - the method cannot statically check which type of object is being read

0
source

Source: https://habr.com/ru/post/1491715/


All Articles