This question already has answers here:
Upcasting and Downcasting in java
(8 answers)
Closed 9 years ago.
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?
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.
When you deserialize an object using the default Java deserializer, you use this code (and you use analogous code when using another deserializer, e.g. the Jackson JSON deserializer)
ObjectInputStream ois = new ObjectInputStream(in);
Object obj = ois.readObject();
You then need to cast obj to its actual type, because readObject() will always return a plain old Object - the method can't statically verify what sort of object is being read
In cases where you want to use polymorphism, it would be nice to work with Student objects, and then "downcast" to use methods specific to Graduate objects.
In general, if you have a method that works with Student objects, that method don't really know at compile-time what specific type of Student objects are passed in. Thus, at run-time, the method should check for the specific type and process accordingly.
Downcasting does help when you're trying to make generic methods. For example, I often see code that parses an XML String into an Object. The Object can then be downcast into the specific Object that you (as the coder) know 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 lets me make a very generic method which does what I want it to do in all cases. Then, when I call it, I can simply downcast the Object into what I know it's going to be. It prevents me from having to make a separate parse method for every object type and improves the readability of my code.
MyFirstClass parsedObject = (MyFirstClass) MyXMLTransformer.fromXML(xml);
Related
I didn't get to understand the polymorphism.
taking this example :
Object o = new String ("foo");
I can't do
o.substring (1,2)
can anyone explain this problem to me ?
This is a consequence of the Liskov Substitution Principle, which states (summarized):
If S and T are objects, and T is a subtype of S, then T may be used where S is expected.
String is-a subtype of Object, so if your assignment operation expects Object, then it will happily accept Object or any of its subtypes.
(Note: Object is not a String. All Strings are Objects, but not all Objects are Strings.)
This doesn't mean you get access to any of the subtype's methods. Given the inheritance hierarchy, an Object has no clue about any of its children's specific methods, nor can it - there is no way to inform an ancestor class of its descendant's capabilities. Because Object has no substring method associated with it, your code correctly results in a compilation failure.
(And it should, given that Object is the ancestor of all classes. There's no guarantee that any given Object is a String.)
The standing advice is to not use an overly inspecific object type (as you go up the hierarchy chain, the capabilities become less specific - you lose functionality as you go up to Object) to accomplish something specific to a more specific type.
You are confusing dynamic and static typing with polymorphism.
Java is a statically typed language so the compiler recognizes that Object doesn't have a substring() method and throws an error. Polymorphism happens after the compilation, when the code is actually executed.
First thing It's not polymorphism.
In Simple way, In your case o object will only call methods which are defined in Object class. If String class has overridden any method of Object class then object o will execute that method of String class otherwise Object o will call Its own method.
For example :
substring() method is only defined in String class So In this case your code will throw exception, however if you call equals() , hashcode() , toString() methods (as these are defined in Object class ) then definition inside String class will get executed because String Class has overridden these methods. And if any of the methods from object Class has not been overridden in its child class then definition inside Object class will get executed.
substring is from the String class, not the Object class. So the below code will work:
String o = new String ("foo");
o.substring(1,2);
This code will not work:
Object o = new String ("foo");
o.substring(1,2);
Since String inherits from Object, String can call Object's methods, such as toString. However, Object does not inherit from String, so an Object cannot call String's methods, such as substring.
for example for data safety I create a class e.g ModelClass and defined some properties and methods and define some list like that
private List<ModelClass> results; then how java will know that what I'm passing is really ModelClass, does it compare all the methods and properties of ModelClass and what object I'm passing in results, I'm how java determine that 2 objects are of same type does it compare all fields and methods to know that yes they are of same type,
Yes I know that when I define type they are of same type would have same objects are method but what happens when we pass object as polymorphic objects
I got this feeling from here when I was learning retrofit, in retrofit when we get response its like:
public void onResponse(Call<MoviesResponse>call, Response<MoviesResponse> response) {
List<Movie> movies = response.body().getResults();
Log.d(TAG, "Number of movies received: " + movies.size());
}
the MovieResponse has same field name which response object return here
Every object has a record of exactly what class it is, which you can see by calling the getClass() method on the said object. This includes the full name of the class (including the package), as well as information about the fields, methods, superclasses, interfaces, etc.
In your case, all it really does is compare these Class objects to make sure they are compatible.
The component which does the most type checking is the Java compiler, and it has the complete source code at its disposal, so it can simply check what type variables were declared to have. (For some libraries you may not have the source code, but also the class files contain this type information.)
For example, in the code snippet
public void add(ModelClass a) {
results.add(a);
}
the compiler knows that results is a reference to List<ModelClass> and that a is a reference to a ModelClass, because that is how they are defined in the source code. So it accepts this code as valid. At runtime, no type checking needs to be performed in this case.
In some cases, in particular when you use the instanceof operator or an explicit cast, the JVM must perform type checking at runtime. For this, every Java object knows its own class. You can obtain the class of an object by calling its getClass() method.
Note that the compiler checks the defined type of the variables, whereas at runtime the type of the object is checked (which the compiler cannot know). The latter is always a subtype of the former. Additionally, for historical reasons, at runtime generic type information is lost. So results.getClass() will return ArrayList.class (or another List implementation), not List<ModelClass>.class (or something like that).
To understand that process you need to know two things:
how to obtain a class information of given object and how to compare two pieces of these.
So how java actually knows the object class?
At runtime classes are same objects as everything else. Every common object stores a reference to the class object. And every class stores a reference to it's superclass.
To store an object in List<Movie> the object type should be directly Movie or it may be it's successor.
Having two classes how do you say if one is the same or at least a successor of another?
Operator instanceof, that's how!
final Movie a = new Movie(...);
final String b = "Not a Movie";
a instanceof Movie; // expression is true
b instanceof Movie; // false
Let's say you have classes hierarchy
Object(0) -> Video(1) -> Movie (2) -> HollywoodMovie (3)
And code
final HollywoodMovie a = new HollywoodMovie(...);
a instanceof Video; // true, how it works?
Second line's instanceof will do these steps:
Checks if type of a has at least two nodes at class hierarchy (because Video is second in it's own hierarchy)
If previous is true checks if the second node is Video
This is an approximation of instanceof work
I think,when you add one object into List<ModelClass> results, the first action is type checking like if(object instanceof ModelClass){...}
This question already has answers here:
Why different types of object reference is allowed in Java?
(7 answers)
Closed 8 years ago.
Parent parent = new Child();
parent.someMethod();
In what situations,assinging like above is useful or what is the logical explanation behind it? instead of the following:
Child child = new Child();
child.someMethod();
In both the cases,Child's method is only going to be called,anyway.So,why this kind of representation is allowed? Isn't it an unnecessary feature allowed in the design?
The only reason I could come up with,depending on some fiddling I did is that,it lets you know that "someMethod()" is not available in the Parent if it is not present in the Parent,at the time of writing "parent.someMethod()"!
Can you please shed some light as to how it is useful/necessary and give me some perspective related to object oriented concepts? I know it relates to Polymorphism here.But I don't find any necessity to use such representations.
Practical real-world example is much appreciated. Thanks.
I check the following SO question,but I don't feel like I have the answers I am looking for.
Using superclass to initialise a subclass object java
It gives you the oppurtinity to behave same to different objects.
For example Object class. Object has a toString() method. And every class extending Object has toString() method. (Every class implicityly extends Object class.)
Now , imagine you have the following objects from different classes. A person(Person class), a car(Car class), a lamp(Lamp class).
You want to write a method that calls each object's toString() method. You have to write 3 different version of this method.
callToString(Person p) {p.toString();}
// A method that accepts person objects.
callToString(Car c){c.toString();}
// A method that accepts car objecs.
callToString(Lamp l){l.toString();}
// A method that accepts lamp objects.
We know that each 3 classes extends from Object class and Object class has toString() method. We can write a method that accepts Object class objects.
callToString(Object o){o.toString();}
Now as this method accepts Object class object, we can use it with Car, Person and Lamp because all of them extends from Object class.
Usage of the new method.
Person john = new Person();
Car ferrari = new Car();
Lamp philips = new Lamp();
callToString(john);
callToString(ferrari);
callToString(philips);
I don't understand why this works in java:
If I have an Integer object in a object, example:
Object myIntObj = new Integer(5);
Now if i do:
System.out.println(myIntObj);
the output is: 5
I now that the Integer class has an ovveride of the toString method but in this case is different (I think).
For the polymorphism, if I have a "child object" in a "father variable" the object doesn't change its real type (in this case Integer) But... it (in the Object variable) can just use the method of the Object Class, so why if I write:
System.out.println(myIntObj);
I can see directly the number 5 and not the reference of this object? Because toString method in the object class by default return just a string of the reference of the object.
like:
Object currentPlayer = new Player();
System.out.println(currentPlayer);
In this case the output is the reference of the Player objecet because is called the toString method in the object class.
So why in the example of before I don't see the reference but directly the number?
by logic, the rules of the polymorphism says that: if u have a "child" object in a "father" variable, this object, inside, remanis the same but he is used like an istance of object, so he can just uses the class object and so just the method of object, so is really strange that I don't see the reference but directly the number.
I hope you understand what I mean.
Your last paragraph where you explain your reasoning is slightly incorrect.
so why in the example of before i don't see the reference but directly
the number? by logic, the rules of the polymorphism says that: if u
have a "child" object in a "father" variable, this object, inside,
remanis the same but he is used like an istance of object, so he can
just uses the class object and so just the method of object, so is
really strange that i don't see the reference but directly the number.
The beginning is correct, but the part I bolded is an incorrect conclusion you drew from it.
You are correct that with polymorphism, the object truly remains whatever type it is, but the reference type (the type of the variable) defines what you can do with it. However, the reference type does not describe what the object does
That is the intent behind polymorphism. It is an abstraction to define what can be done separately from how it works. For example, if you have this example:
public class Vehicle {
public int getWheelCount() {
return 1;
}
}
public class Car extends Parent {
public int getWheelCount() {
return 4;
}
public void blowHorn() {
System.out.println("Honk honk!");
}
}
public class Bicycle extends Parent {
public int getWheelCount() {
return 2;
}
}
Car car = new Car();
car.getWheelCount(); // 4
car.blowHorn(); //"Honk honk!"
Vehicle v = new Car();
v.getWheelCount() // 4
v.blowHorn(); // COMPILE ERROR HERE! Unknown method
Bicycle b = new Bicycle();
b.getWheelCount(); // 2
Vehicle v = new Bicycle();
v.getWheelCount(); // 2
What you can conclude from this is that when over-riding a method in a sub-class, the child version is always called. A car is always a car whether you are referring to it as a vehicle or as a car. But by referring to it as a vehicle, you are limited to invoking methods which are defined on all vehicles.
To tie it to the example, all Vehicle objects have a wheel size, therefore getWheelCount() is always callable whether it's Vehicle.getWheelCount() or Car.getWheelCount(). However, Car.getWheelCount() is what executes because Car over-rides it.
If the reference type is Vehicle, you cannot call blowHorn() because that method is only available on Car.
Going back to your example, an Integer is an Integer.
Object i = new Integer(5);
i.toString(); // 5
This prints 5 because i is an integer. The Integer class over-rides toString. The reference type (the type you are referring to the object as) only determines which methods you can call, but not which parent/child class's version of the method is called.
By defining it as Object this means you will only have access to methods that are defined in the Object class.
This includes toString().
So when you instantiate new Player() you still only have access to the methods from Object, but if you override this (like Integer.toString() does), you will still have the output as defined in the instantiated class.
PS: Father -> Parent
This is how the concept of overriding methods works: once an object somewhere in the inheritance hierarchy provides an implementation, it is this implementation that is going to be called, unless it is overridden by another class further down the inheritance hierarchy.
Since java.lang.Integer provides an override of toString(), this override is called instead of the implementation provided by the java.lang.Object.
There is no difference between System.out.println(myIntObj) and System.out.println(myIntObj.toString()), because println will call toString internally on all objects which it does not know how to print.
The reason your Player class behaves differently is that it does not override toString(). If it did, you would see its results printed. With no override, however, the default implementation provided by java.lang.Object is called, which prints some generic object info.
Object myIntObj = new Integer(5);
Here you're creating a new Integer instance, not a bare Object instance. The fact that you're assigning it to an Object reference doesn't transform it into a bare Object. It's still an Integer, but you can reference it as an Object because it extends Object. So when you call myIntObj.toString(), you're calling that instance's toString() method. That instance turns out to be an Integer instance. And so Integer.toString() is called.
Object currentPlayer = new Player();
In this case the same rules apply when calling currentPlayer.toString(): you're actually calling Player.toString(). If Player class does not override toString(), then first ascending parent class toString() implementation is called. If Player directly extends Object, then Object.toString() is called, but if for example Player extends Human and Human extends Object, then Human.toString() is going to be called if it exists. If not, then Object.toString().
Consider this case where Employee has a subclass Manager that has a method getDetails() overridden,
Employee e=new Employee();
Employee m=new Manager();
If you invoke e.getDetails() you will get the behavior associated with Employee.
If you invoke m.getDetails() you will get the behavior associated with Manager.
In general, you get the behavior associated with the object to which the variable refers at runtime. This behavior is often referred to as virtual method invocation.
So the reason why you are getting the behavior associated with Integer when your reference is an object is because you are referring to an Integer object at runtime.
In class B, how can I create an object of class A other than the process of object creation (i.e. without creating an object having null)?
class A
{
public int one;
A(A a)
{
a.one=1;
}
}
class B
{
public static void main(String...args)
{
//now how to create an object of class A over here.
}
}
To construct an object of type A you need to pass to the constructor either a reference to another object of type A, or else the null reference. So you have only two options:
A a1 = new A(null);
A a2 = new A(a1);
The first time you create an object of type A you must use the null reference because you don't have any other objects of type A.
Update
After you changed your question, I don't think it's possible to construct an object of type A.
If I understand your question correctly, you want to create an object a without having to pass it a pre-existing object of the same type.
To do so you have to add a constructor to class A that does not take a parameter of type A or modify the existing one:
class A
{
A() {
// Constructor logic.
}
A(A a) {
// Constructor logic when passing an existing object of the same type, perhaps to create a clone.
}
}
If for some reason you can't modify class A, you'll have to follow Mark Byers' answer and pass a null reference to the constructor.
Update
With the update to your code, this problem (or thought experiment) is unsolvable: class A can not be instantiated as written.
You cannot normally do this in Java.
However, it's possible with heavy cheating. Don't do this in production code. But for the sake of argument:
1) With Mockito (But won't work with a security manager):
import org.mockito.Mockito;
class B {
public static void main(String... args) {
A mockedA = Mockito.mock(A.class);
A realA = new A(mockedA);
System.out.println(realA);
}
}
2) Here's another way to do it overriding finalize().
Only way to create A object is by giving him other A object in constructor, but that other A object also needs another A object in constructor. This will stop only when you put null reference in constructor.
Edit
My answer was based on your previous version of code. Now you can't create object because you can't put null in constructor (null desn't have one field). If you want to create A object, you have to do test for null in constructor like if (a!=null){ a.one=1;} and pass null or already created A object in constructor.
If A is sealed (not editable) you could only extend that class and give the one a default constructor to pass it into a new instance of A. There is no other solution without modifying the source code of A.
You can not instantiate A in your example. It is a chicken and egg problem. You need an instance of A to create an instance of A, but you can not create an instance of A without having an instance of A.
So, without changes to A (be it either adding a 'null' check or adding a default constructor) you can not create an instance of A in this scenario.