How does Java Object casting work behind the scene? [duplicate]
Solution 1:
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"?
Solution 2:
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.
Solution 3:
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
}
Solution 4:
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.