How subclass reference-variable can point to superclass object - java

A subclass reference-variable cannot refer to superclass:
Child c1 = new Parent(); // Error Incompatible types
So we are telling the compiler i known the type of object:
Parent p1 = new Child();
Child c1 = (Child) p1;
My question is how the Child-class reference variable can point to the super-class object without rising error in run time and if you use casting it changes the state of that type e.g:
int num = (int)6.6; // Result = 6
Something must be happens when p1 object is casted to Child-class.

You're confusing a reference or object with a reference variable, and the difference between the two is a key concept that underlies object-oriented programming principles.
Here:
Parent p1 = new Child();
Child c1 = (Child) p1;
p1 is not a super-class object. Rather it's a super-class variable that refers to a child object in your code. So on the second line, your Child variable, c1 is being assigned a Child object. Note that this code will be allowed by the compiler even if p1 held a super's object, but then the JVM would throw a class cast exception when the code is run.

Related

what happens Object class reference variable that refers inherited class during runtime?

public class A{}
I have created a class with name 'A' and in main class i wrote this statement below:
Object m = new A();
after compilation time, what happens to variable m ? I mean, won't reference type of m cast to its actual type which means 'A' ? If so, why i'm not getting any runtime error when i write this statement below :
m = new Object();
Object class is parent class. So, is it possible to cast child class reference variable to parent class variable ?
I hope i could tell my problem clearly. sorry for my english, thanks for all help.
m is a reference that can point to any Object or any subclass of Object. That is why
Object m = new A();
works. Note that m itself keeps no knowledge of the type of object it actually points to at runtime. Which is why you can't do
...m.someMethodOfA()... // Fails at compile time
The compiler knows m can point to only Object instances, and using m you can access only members of Object, even if the runtime type is something else.
At runtime, as long as m still points to an A instance, then you can do things like
...((A)m).someMethodOfA()...
Note it is you that knows this and you encode that knowledge by using the down-cast from Object to A. So later in the program if your code does:
m = new Object();
the old reference to an A instance is forgotten, but since m never knew it originally pointed to an A, there's no problem with this assignment.
After this, however, the down-cast to A, which was previously valid, will now result in ClassCastException.
what happens to variable m ?
After Object m = new A(); is run, m stores a reference to the instance of A you just created.
There is no casting, casting a variable x to a type T looks something like this: (T)x, and you are not doing that here. There is a type conversion from A to Object, because Object and A are different types, but nothing (no checks etc) actually needs to be done at runtime, because Object is a superclass of A, so the conversion always succeeds.
If so, why i'm not getting any runtime error when i write this statement below :
m = new Object();
This line stores a reference to an Object object in m, and discards whatever was in m before, so whatever was stored in m is irrelevant.
It may be worth pointing out that the lines Object m = new A(); and m = new Object(); could be written in a longer form as
Object m;
m = new A();
m = new Object();
where it is more visible that m itself exists without an object reference being stored in it already. So it just "happens" that the next line puts an A reference into it, but m itself refers to an Object, as its declaration states.
It would be very different if you used the `var` keyword (relatively new thing, available from Java 10), where the compiler deducts a fitting type for the right side of the initialization (and thus `var`s have to be initialized immediately):
var m = new A();
m = new Object();
this will die, not in runtime, but in compliation time already. The first line implicitly becomes A m = new A();, and thus m = new Object(); doesn't make sense anymore.

How can a superclass variable hold data member values that only exist in subclass?

I'm trying to understand how a variable of type superclass can store values in data members that only exist in the subclass.
For example in Java, lets say class Child extends Parent. Child has a data member childMember (let's assume it's an int).
This is legal in Java:
Parent parentObject = new Child();
((Child)parentObject).childMember = 5;
But how can the parentObject store a value for childMember since it is of type Parent and Parent doesn't have the childMember? I know it is being cast to set the value, but how does it even have the data member to be able to store it since it isn't a child object?
In this code:
Parent parentObject = new Child();
((Child)parentObject).childMember = 5;
The parentObject object's actual/runtime class is Child, and that explains why all works.
But how can the parentObject store a value for childMember since it is of type Parent and parent doesn't have the childMember?
This question is more applicable to this code:
Parent parentObject = new Parent();
((Child)parentObject).childMember = 5;
In this case, however, the cast ((Child)parentObject) will not work, and Java will raise a ClassCastException at runtime, as you seem to expect.
First of all the reference is of type Parent, the object it points to is of type Child, thus your entire logic works as detailed in the other answer.
But this is a pretty trivial example, let's do a funner one:
static class Parent {
public int x = 5;
}
static class Child extends Parent {
public int x = 3;
}
How many x's does Child have? Well...
Arrays.stream(Child.class.getFields())
.map(Field::getName)
.forEachOrdered(System.out::println); // x AND x again
How do you then access each of them?
Child c = new Child();
System.out.println(c.x); // 3
Parent p = c;
System.out.println(p.x); // 5

Questions on polymorphism in Java

I was trying to understand Polymorphism in Java but I could not understand certain things in App.java.
Q1) Why are we able to do p2=tree; even though p2 is reference to class Plant and tree is an object of class Tree?
Q2) Why does it say Type Mismatch:cannot convert from Plant to Tree when I try to do this :
tree=new Plant();
Q3) Why does p2.shed() cause an error even though the output of b2 is true? If p2 is instance of tree it should be able to access Tree methods.
App.java
public class App {
public static void main(String[]args){
Plant p1 = new Plant();;
Plant p2 = p1;
Tree tree = new Tree();
boolean b1= tree instanceof Plant;
p2=tree;
boolean b2= p2 instanceof Tree;
System.out.println(b1+" "+b2);
p2.grow();
tree.shed();
//p2.shed(); ---- Why is this an error?
}
}
Plant.java
public class Plant {
public void grow(){
System.out.println("Plant growing");
}
}
Tree.java
public class Tree extends Plant {
#Override
public void grow() {
System.out.println("Tree growing");
}
public void shed(){
System.out.println("Tree shedding");
}
}
Answers:
1) Plant is the Parent Class of Tree.
I hope you know That when we do Plant p = new Plant(); p is the reference.
And new Plant() is the actual Object.
So,a Parent Reference can point to a child object. So you can do p2=tree or
Plant p2 = new Tree()
2) Now remember the point I wrote above. A Parent Reference can point to a child object. BUT A Child Reference CANNOT point to a Parent Object
i.e you can't do Tree t = new Plant();
3) You cannot do p2.shed() even thought p2 actually points to a Tree object and not Plant object. Because of the Reference restriction.
See the Reference variable "p2" is of Type Plant and is pointing to an object of Tree Type. But the reference p2 doesn't know that it is pointing to an object of Tree type. It thinks that it is pointing to an object of Plant type only.
So when you do p2.grow() It thinks that it is calling the grow() method of Plant class because p2 is a reference of type Plant.
But when when CPU(The executor of your code) goes to the object that p2 is pointing to, CPU finds out that this is actually a Tree object and calls grow() method of Tree and not Plant class and hence it print "Tree is Growing " and not "Plant is growing".
When you do p2.shed() you get Compiler Error. Because in Plant class there is no such method called shed(). Even though the actual object that p2 points to may have a Tree object with shed() method present. The compiling does not happen.
Because the reference (p2) doesn't know about the new method shed() that is present in child object.
Read :: Herbert Schildt - Java A complete reference. The language is very simple.
After you gain some experience in Java read Kathy Sierra SCJP 6 to understand Java in depth.
I'm assuming that you wrote these examples yourself and you understand how using the extends declaration in your classes works. It also looks like you are attempting to extend the class Plant, but it isn't declared as an abstract class. Anyway:
To one of your points, the reason that tree=new Plant(); is throwing an error is because with polymorphism, you have to work from broad to specific.
A Tree is a type of Plant, but a Plant is not a type of Tree, so saying plant = new Tree(); would be valid, which answers your first question.
Lastly, b2 is not true since p2 is a Plant, because as we said before that a Plant is not a type of Tree.
The reason it is giving you an error, however, is that since p2 is of the class Plant (not Tree), it only has one method available, which is grow(), and you are trying to call the shed() method, only available to Trees.
Q1)Why are we able to do p2=tree; even though p2 is reference to class Plant and tree is an object of class Tree?
this is valid
The p1, referencing to a Parent Object, cannot be cast to Child
because a Parent is not a Child. But a Child is a Parent since the
Child inherits all the methods in Parent class. However, if p1 is
referencing to a Child object or a subclass of Child, then you can
cast p1 to Child.
Parent p1=new Parent();
Child c1=new Child();
p1=c1;
Q2) Why does it say Type Mismatch:cannot convert from Plant to Tree when I try to do this : tree=new Plant();
Parent p1=new Parent();
Child c1=new Child();
c1=(Child)p1;
You cannot cast a Child object to its Parent Though it will
compile ,on runtime java identifies that p1 holds a reference which is
not assignment compatiable with c1 and will throw
java.lang.ClassCastException
Q3)Why p2.shed() an error even though the output of b2 is true? If p2 is instance of tree it should be able to access Tree methods.
Reference variable "p2" is of Type Plant and is pointing to an Object
of Tree Type. So it will be able to access the method of Plant class
p2 is defined as Plant and It only can call those methods defined in Plant class, but with the logic of instance Tree. How the method shed is not defined in the Plant class, the variable p2 (of Plant class) not know the method shed, by this it can not call at method shed.
Regards.

Couple java questions regarding type casting and inheritance

Hello I have a few questions regarding type casting and inheritance. I have been doing some reading and I understand the point and basics of type casting. However, I don't fully understand where I can and can't use it.
Consider this class:
class A{
public A(){}
}
A temp = new A();
temp = (Object)temp;
This code gives me the error "Cannot convert from type Object to type A". However, wouldn't this be converting from type A to type Object? Can you not type cast up the hierarchy?
Now my second question regards inheritance and such.
When you type:
Object temp = new A();
what is really happening? Is temp an A or is it an Object?
Here the excerpt from JLS 8.1.3:
If the class declaration for any other
class has no extends clause, then the
class has the class Object as its
implicit direct superclass.
Of course, Object itself is a bit special (JLS):
Each class except Object is an
extension of (that is, a subclass of)
a single existing class (§8.1.3) and
may implement interfaces (§8.1.4).
Every Class is a descendant of Object.
In your case, you are trying store an object of A into a Class object called A. This isn't going to work. You need to do:
Object testObject = (Object)temp;
This will store the Object into testObject, which has the type Object that you casted to.
Here it is working on ideone.
It's just because you can't assign superclass object to the subclass reference.
So you can't do:
temp = (Object)temp;
because it's the same as:
Object newObject = new Object();
A temp = newObject;
You will get the same compile error here.
Of course you can do something like that:
Object newObject = new Object;
A temp = new A();
newObject = temp;
You can do it because you can assign subclass to the superclass reference
The problem is in the last line. First you promise Java that temp is of type Object by the statement:
(Object) temp
Afterwards you try to assign an object that the compiler thinks is of type Object to a variable that should be of type A. So to conclude, the part where you cast temp to type Object is fine, the problem is when you afterwards try to assign it to a variable expecting something of type A.
For your second question, temp is an A. When creating an object with the new keyword, the type of the object will always be whatever comes right after. In your case A. Afterwards you then assign temp to a variable of type Object, but that does not change the actual type of temp. Having a variable of some type X just tells you that whatever the variable is pointing to is a subtype of X.
A a = (Object)temp;
"Cannot convert from type Object to type A". However, wouldn't this be converting from type A to type Object? Can you not type cast up the hierarchy?
You are correct that
(Object)temp;
is converting temp, which is an A to an Object. However, that's not what the compiler is complaining about. Now that you have, effectively,
A a = anObjectNOTAnA
(A = ... is invalid code. I've changed it to A a = ....)
It's saying that you cannot convert an Object back to an A, unless you explicitely cast it and potentially suppress the unchecked-cast warning:
A a = (A)anObjectNOTAnA
or
#SuppressWarnings("unchecked")
A a = (A)anObjectNOTAnA
Regarding your other question:
Object temp = new A();
What is really happening? Is temp an A or is it an Object?
When you cast an object of any type, it never changes the actual type of the underlying object. A new A() is always an A, whether its
A a = new A();
or
Object objButReallyA = new A();
or
#SuppressWarnings("unchecked")
A a = (A)((Object)new A());
If an A is stored in an Object, it's just a different "view" of the same object. In order to use the A specific functions, however, you must first revert it back to the A view:
objButReallyA.getAOnlyField(); //compile error
((A)objButReallyA).getAOnlyField(); //Okay

How does Java Object casting work behind the scene? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does the Java cast operator work?
Java casting implementation
I am always wondering how object casting works in Java. I understand for primitive type it will be more like in binary representation level, but what about Object? Is it kind of like Polymorphism or dynamic binding in that everything will be determined at runtime? For example:
class Parent{
void A(){}
}
class Child extends Parent{
#Override
void A(){}
}
Parent p = new Parent();
Child c = (Child) p;
How does this work behind the scene? Does it create a new instance of Child? And also, what happens if you try to cast:
Child b = (Child) new Object();
And last one, when casting a primitive to a wrapper class:
Double d = (Double) 3.3;
I know you don't necessary need to cast it, but what if you do? Is there anything significant that happens on the backend?
No new objects are created in the system when you use explicit casting (except in your last case, where you cast a primitive type to an object wrapper, since double is not an object like Double is). Note that this explicit cast isn't necessary due to Java's autoboxing feature.
In your (Child) new Object() scenario, you will receive a ClassCastException because an Object is not a Child (although the opposite is true).
The answer to your first scenario is the most complicated. Essentially the parent class is treated like an interface might be. When you cast the Child to the Parent, only the Parent API is available. However, the overridden method will still be called. So, if you do:
Parent p = (Parent) new Child();
p.a();
... the Child's public void a() will be called, even though it is being seen through the lens of the Parent class. However if you were to have a second method in the Child that the Parent does not have (let's say public void b() for instance), you would not be able to call that without casting the object back to a Child.
"Behind the scenes", as you say, the only new thing that is created is another object reference which points to the same object. You can have as many references as you like to the same, singular object. Consider this example:
Parent p = new Parent();
Parent p1 = p;
Parent p2 = p;
Parent p3 = p2;
Here, there are four references (p, p1, p2, and p3) each of which points to the same object you created with the new Parent() declaration.
I would probably argue on the philosophical point, though, that this creation of new references is actually explicit rather than behind the scenes when you say Parent p = something.
Links:
http://en.wikipedia.org/wiki/Primitive_wrapper_class
http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html
http://docs.oracle.com/javase/7/docs/api/java/lang/ClassCastException.html
http://docs.oracle.com/javase/tutorial/java/IandI/override.html
Is Java "pass-by-reference" or "pass-by-value"?
The simple answer to your main question is No.
All casting happens at syntax checking time.
Casting affects how the syntax checker looks at the object,
it does not affect the object itself, a Child cast to be a
Parent, is still a Child.
However the cast is only checked at Runtime.
Which is why it is dangerous and should not be used
unless there is no other way.
Accodring to this: checkcast, what it does is to verify if the reference is assignable. If it is, the stack is not changed and the operation on that reference are kept.
So if you have:
Child c = ( Child ) anyObject;
c.sayHi();
If the cast success, then the method sayHi could be invoked:
If objectref can be cast to the resolved class, array, or interface type, the operand stack is unchanged; otherwise, the checkcast instruction throws a ClassCastException.
Here's the "bytecode"
$ cat CastDemo.java
class Parent {}
class Child extends Parent {}
class Main {
Child c = (Child) new Parent();
}
$ javap -c Main
Compiled from "CastDemo.java"
class Main {
Child c;
Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: new #2 // class Parent
8: dup
9: invokespecial #3 // Method Parent."<init>":()V
12: checkcast #4 // class Child
15: putfield #5 // Field c:LChild;
18: return
}
First of all, be very careful not to confuse conversion with casting. They may share the surface syntax, but are very different processes.
In Java you can downcast an Object to any type, but at runtime you'll get a ClassCastException if the object is not in fact compatible with the target type. This happens at the bytecode level: there is a bytecode instruction dedicated to downcasting.
Child c = (Child) new Object();
will unconditionally result in a ClassCastException.
Double d = 3.3; // note: no explicit casting needed
will perform autoboxing into an instance of Double. So here, a new instance is actually created.
A normal, successful dowcast may look like this:
Object o = "a";
String s = (String)o;
Here, no objects are created: only the value of o is copied into s. The value is a reference.
Downcasting an object is not doing anything to that object. Behind the scenes the compiler will inject checkcast bytecode operation. If p is not really an instance of Child, exception will be thrown. Otherwise you basically have a (type-)safe reference to the same object with different, more specific type.
Child b = (Child) new Object();
This fails with ClassCastException. JVM compares getClass() of new Object() with Child.class. Since Object.class is not a subclass of Child.class, exception is thrown.
Double d = (Double) 3.3;
Here, casting isn't even necessary, this works as well: Double d = 3.3. Behind the scenes this is translated to:
Double d = Double.valueOf(3.3);
This is known as Autoboxing.

Categories