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.
Related
I'm preparing for the SCJP (recently rebranded as OCPJP by Oracle) and one particular question that I got wrong on a mock exam has confused me, the answer description doesn't explain things clear enough.
This is the question :
class A
{
int x = 5;
}
class B extends A
{
int x = 6;
}
public class CovariantTest
{
public A getObject()
{
return new A();
}
public static void main(String[]args)
{
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
class SubCovariantTest extends CovariantTest
{
public B getObject()
{
return new B();
}
}
The answer is 5, but I chose 6.
I understand that overriding applies to methods at runtime, and not variables, but the way my mind interpreted that println was :
call getObject on c1
c1 is actually a SubCovariantTest object, and has a valid override
for getObject(), so use the overridden method
The override returns B, so grab x from B which is 6
Is it a case of the JVM ignoring the getObject() part, and always taking x from c1 as variables are associated at compile time?
Although the override is done properly for SubCovariantTest the answer is 5 because of how the variable c1 is declared. It is declared as a CovariantTest and not as a SubCovariantTest.
When c1.getObject().x is run, it does not know that it is a SubCovariantTest (no casting was used). This is why 5 is returned from CovariantTest and not 6 from SubCovariantTest.
If you change
System.out.println(c1.getObject().x);
to
System.out.println(((SubCovariantTest) c1).getObject().x);
you will get 6 as you expected.
Edit: As pointed out in the comments
"fields are not polymorphic in Java. Only methods are. The x in the subclass hides the x in the base class. It doesn't override it." (Thanks to JB Nizet)
Okay I know this is a bit late to reply to this question but I and my friend had the same problem and the answers already here didn't quite clear it for us. So I'll just state what problem I had and how it makes sense now :)
Now I do understand that fields don't get overrided but instead they get hidden as miller.bartek pointed out and I also understand that overriding is for methods and not fields as Scott points out.
The problem I had however was this. According to me,
c1.getObject().x
This must transform into:
new B().x // and not newA().x since getObject() gets overrided
And that evaluates to 6.
And I couldn't get why the variable of class A (super-class) is being called by an object of class B (sub-class) without having explicitly asked for such a behaviour.
And guessing from the wording of the question, I feel the OP had the same question/doubt in mind.
My Answer:
You get a hint from Elbek's answer. Put the following lines in the main method and try to compile the code:
A a = c1.getObject(); //line 1
B b = c1.getObject(); //line 2
You'll notice that line 1 is completely legal while line 2 gives compilation error.
So when the function getObject() is being called, the CovariantTest (super) function IS getting overrided by SubCovariantTest (sub) function since that is valid overriding in the code and c1.getObject() WILL return new B().
However, since the super-function returns a reference of class-type A, even after getting overrided, it must return a reference of class-type A unless ofcourse we type-cast it. And here, class B is a class A (due to inheritance).
So practically, what we're getting from c1.getObject() is not
new B()
but this:
(A) new B()
That is why the output comes out to be 5 even though an object of class B is returned and class B has value of x as 6.
The technical term for what is happening here is "hiding". Variables names in Java are resolved by the reference type, not the object they are referencing.
A object has a A.x variable.
B object has both A.x and B.x variables.
However instance methods with the same signature are "overridden" not "hidden", and you cannot access the version of a method that is overridden from the outside.
Note that hiding also applies to static methods with the same signature.
Your mock question in a simplified form (without overriding):
class A {
int x = 5;
}
class B extends A {
int x = 6;
}
public class CovariantTest {
public static void main(String[] args) {
A a = new B();
B b = new B();
System.out.println(a.x); // prints 5
System.out.println(b.x); // prints 6
}
}
You are calling method from c1: System.out.println(c1.getObject().x);
c1 reference type is:
public class CovariantTest
{
public A getObject()
{
return new A();
}
public static void main(String[]args)
{
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
so for this: c1.getObject() return type is A. from A you getting directly attribute not method, as you mention java does not override attributes, so it is grabbing x from A
When methods are overridden, subclass methods are called, and when variables are overridden the superclass variables are used
When the child and parent class both have a variable with same name child class's variable hides parent class's variable and this is called variable hiding.
While variable hiding looks like overriding a variable similar to method overriding but it is not, Overriding is applicable only to methods while hiding is applicable variables.
In the case of method overriding, overridden methods completely replaces the inherited methods so when we try to access the method from parent's reference by holding child's object, the method from child class gets called.
But in variable hiding child class hides the inherited variables instead of replacing, so when we try to access the variable from parent's reference by holding child's object, it will be accessed from the parent class.
When an instance variable in a subclass has the same name as an instance variable in a superclass, then the instance variable is chosen from the reference type.
You can read more on my article What is Variable Shadowing and Hiding in 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.
I have two classes as given below.
class One {
void disp() {
System.out.println("Super class disp() method");
}
void show() {
System.out.println("Super class show() method");
}
}
class Two exntends One{
void disp(){
System.out.println("Sub class disp() method");
}
}
class TestInheritance {
public static void main(String args[]) {
One o = new Two();
o.disp();
Two t = (Two) new One();
}
}
What happens in terms of memory when we convert sub class object to super class object.?
One o = new Two();
What happens in terms of memory when we convert super class object to sub class object.?
Two t = (Two) new One();
What happens in terms of memory when we convert sub class object to super class object.?
One o = new Two();
What happens is that a Two instance is created, and the reference is assigned to o.
This doesn't change the Two instance in any way. It is not "converted". It remains a Two.
What happens in terms of memory when we convert super class object to sub class object.?
Two t = (Two) new One();
What happens is that a One instance is created, and its type is tested to see if the One is a Two. Since it isn't ... a ClassCastException is thrown immediately.
(Following that, the One instance that was just allocated will be unreachable and a candidate for garbage collection ... the next time that the GC runs.)
In fact, you probably meant this:
One o = new Two();
Two t = (Two) o;
What happens in this case is that the first statement creates a Two instance and assigns its reference to o. Then in the second statement, the type of the object refered to by o is tested to see if it "is-a" Two. Since it is ... the reference is then assigned to t.
Once again, this doesn't change the Two instance in any way. It is not "converted". It remains a Two.
Can you give some detail about how the memory will be allocated.? I mean "when Two class object is created, memory will be allocated for Two's members and One's members as well (reason being One is super class for Two)" and will be referred by 't'.
That is correct
When we do "One o = new Two()", we will be able to access only One class members.
That is correct.
When we are converting like this (sub class object pointed by super class reference), what exactly happens internally..?
All that happens is that the compiler & runtime "forget" that o actually refers to a Two, and only permits you to use the reference to access the fields / methods defined by the One class.
Casting doesn't change anything its just a way of treating object of one type as object of some other (allowable) type.
First of all your 2nd condition Two t = (Two) new One(); is not possible because
subclass object can not hold the object of super class.
In case of memory JVM treat as method overriding in case of disp() method
so One o = new Two() holds the properties of super class One as well as subclass Two.
Method are belonging to method area of the particular class
anCasting doesn't do anything, it just tells the compiler that object of type A is actually of object of type B, and therefore I can call the methods of object B on it. At compile time, all the casting is erased, you just better hope that the method call to the object actually succeeds, otherwise you will get a run time error of some description.
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
I'm preparing for the SCJP (recently rebranded as OCPJP by Oracle) and one particular question that I got wrong on a mock exam has confused me, the answer description doesn't explain things clear enough.
This is the question :
class A
{
int x = 5;
}
class B extends A
{
int x = 6;
}
public class CovariantTest
{
public A getObject()
{
return new A();
}
public static void main(String[]args)
{
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
class SubCovariantTest extends CovariantTest
{
public B getObject()
{
return new B();
}
}
The answer is 5, but I chose 6.
I understand that overriding applies to methods at runtime, and not variables, but the way my mind interpreted that println was :
call getObject on c1
c1 is actually a SubCovariantTest object, and has a valid override
for getObject(), so use the overridden method
The override returns B, so grab x from B which is 6
Is it a case of the JVM ignoring the getObject() part, and always taking x from c1 as variables are associated at compile time?
Although the override is done properly for SubCovariantTest the answer is 5 because of how the variable c1 is declared. It is declared as a CovariantTest and not as a SubCovariantTest.
When c1.getObject().x is run, it does not know that it is a SubCovariantTest (no casting was used). This is why 5 is returned from CovariantTest and not 6 from SubCovariantTest.
If you change
System.out.println(c1.getObject().x);
to
System.out.println(((SubCovariantTest) c1).getObject().x);
you will get 6 as you expected.
Edit: As pointed out in the comments
"fields are not polymorphic in Java. Only methods are. The x in the subclass hides the x in the base class. It doesn't override it." (Thanks to JB Nizet)
Okay I know this is a bit late to reply to this question but I and my friend had the same problem and the answers already here didn't quite clear it for us. So I'll just state what problem I had and how it makes sense now :)
Now I do understand that fields don't get overrided but instead they get hidden as miller.bartek pointed out and I also understand that overriding is for methods and not fields as Scott points out.
The problem I had however was this. According to me,
c1.getObject().x
This must transform into:
new B().x // and not newA().x since getObject() gets overrided
And that evaluates to 6.
And I couldn't get why the variable of class A (super-class) is being called by an object of class B (sub-class) without having explicitly asked for such a behaviour.
And guessing from the wording of the question, I feel the OP had the same question/doubt in mind.
My Answer:
You get a hint from Elbek's answer. Put the following lines in the main method and try to compile the code:
A a = c1.getObject(); //line 1
B b = c1.getObject(); //line 2
You'll notice that line 1 is completely legal while line 2 gives compilation error.
So when the function getObject() is being called, the CovariantTest (super) function IS getting overrided by SubCovariantTest (sub) function since that is valid overriding in the code and c1.getObject() WILL return new B().
However, since the super-function returns a reference of class-type A, even after getting overrided, it must return a reference of class-type A unless ofcourse we type-cast it. And here, class B is a class A (due to inheritance).
So practically, what we're getting from c1.getObject() is not
new B()
but this:
(A) new B()
That is why the output comes out to be 5 even though an object of class B is returned and class B has value of x as 6.
The technical term for what is happening here is "hiding". Variables names in Java are resolved by the reference type, not the object they are referencing.
A object has a A.x variable.
B object has both A.x and B.x variables.
However instance methods with the same signature are "overridden" not "hidden", and you cannot access the version of a method that is overridden from the outside.
Note that hiding also applies to static methods with the same signature.
Your mock question in a simplified form (without overriding):
class A {
int x = 5;
}
class B extends A {
int x = 6;
}
public class CovariantTest {
public static void main(String[] args) {
A a = new B();
B b = new B();
System.out.println(a.x); // prints 5
System.out.println(b.x); // prints 6
}
}
You are calling method from c1: System.out.println(c1.getObject().x);
c1 reference type is:
public class CovariantTest
{
public A getObject()
{
return new A();
}
public static void main(String[]args)
{
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
so for this: c1.getObject() return type is A. from A you getting directly attribute not method, as you mention java does not override attributes, so it is grabbing x from A
When methods are overridden, subclass methods are called, and when variables are overridden the superclass variables are used
When the child and parent class both have a variable with same name child class's variable hides parent class's variable and this is called variable hiding.
While variable hiding looks like overriding a variable similar to method overriding but it is not, Overriding is applicable only to methods while hiding is applicable variables.
In the case of method overriding, overridden methods completely replaces the inherited methods so when we try to access the method from parent's reference by holding child's object, the method from child class gets called.
But in variable hiding child class hides the inherited variables instead of replacing, so when we try to access the variable from parent's reference by holding child's object, it will be accessed from the parent class.
When an instance variable in a subclass has the same name as an instance variable in a superclass, then the instance variable is chosen from the reference type.
You can read more on my article What is Variable Shadowing and Hiding in Java.