I am learning for a JAVA Programmer I certificate and among questions there is one I can't understand:
//Given:
interface I{}
class A implements I{}
class B extends A {}
class C extends B{}
//and
A a = new A();
B b = new B();
Identify options that will compile and run without error.
A. a = (B)(I)b;
B. b = (B)(I)a;
C. a = (I)b;
D. I i = (C)a;
Now I know that the answer is A) but I don't get it, if the class B is a child of class A, then 'a' can be equal to 'b' without casting, why is the answer B) wrong? What does even casting (B)(I) means?
B extends A. So you can cast instances of B to A but not the other way around. The code will compile, but will throw a ClassCastException at runtime.
Trying to cast to a descendant class is called downcasting. The cast to 'I' in this case is what would allow that code to compile, but result in the ClassCastException being thrown.
Parent reference can be used to hold child objects. Thus below all are correct.
A a = new A();
B b = new B();
I i = new A();
a = new B();
b = new C();
Below has attempted to cast an object to a subclass of which it is not an instance.Thus below will throw the CCE.
b = (B)(I)a;
c = (C)(I)a;
You may check the same as System.out.println(a instanceof C);
Related
I am preparing for java certification and unable to find any concept or logic behind this.
Can anyone help me understanding the concept of multiple typecasting. I can understand the one level of type casting but I am not getting any information for these conversions.
Here is the sample I am trying to understand.
interface I{
}
class A implements I{
}
class B extends A {
}
class C extends B{
}
A a = new A();
B b = new B();
Now option 1 don't have any error at compile time or runtime, while 2nd option is having error. I run it in eclipse but unable to understand the logic behind this.
1. a = (B)(I)b;
2. b = (B)(I)a;
Your question is a bit vague but I'll see if I can help.
So you have your interface I and classes A, B and C.
You can now do things like these:
I i1 = new A();
I i2 = new B();
I i3 = new C();
This is possible because, by inheritance, all the classes A, B and C implement I.
You can also do
A a1 = new B();
A a2 = new C();
for almost the same reason (difference being they are extending A rather than implementing an interface).
You probably guessed by now that you can also do
B b1 = new C();
What you can't do is something like
B b = new A(); // Type error
C c = new B(); // Type error
B b2 = (B)new A(); // ClassCastException
This is not possible since the type A does not extend from B.
In general you don't need to explicitly type cast in these cases.
I i = (I)new A(); // <- not necessary
It can be necessary in the opposite direction however:
I i = new B();
B b = (B)i; // <- cast is needed.
This works if and only if i is actually of type B (or C). If the object i is not of type B or a type that extends from B you will get ClassCastException.
Now for your question
Both your two options are a bit strange. Double casting is not something you would normally do. the cast to I is unnecessary.
With that said, 1) will work and 2) will not. Your object b cannot be assigned a because A does not extend from B.
Edit
To be clear, when you instantiate an object, for example
A a = new A();
The actual object (I'm going to call it o) is an instance of class A. You also have an object reference called 'a' which is typed as A which refers to the object o.
When you assign other object references, the type of the actual object doesn't change. When assigning a reference, the type of the object must be the same type as the reference or of a type that inherits from the referred type.
For example, you can assign a reference of type I:
I i = a;
This assigns the reference i to the same object that a refers to which is the object o. Note that o is still of type A.
System.out.println(i instanceof A);
will print
true
Suppose I have three classes A, B and C.
C extends B and B extends A.
A implements an interface InterfaceA
B implements interfaces InterfaceB1 and InterfaceB2.
What is the best way to find all possible combinations of downcasting?
What I mean is?
Suppose we have:
B b = new B();
InterfaceA i = (InterfaceA)(A)(B) b.
How can we easily know if this compiles and if it will cause a classcastException without an IDE?
I know how objects and references work and have a decent understanding of polymorphism in Java.
I started to draw a sketch of the class and interface structure.
EDIT: I know my example is not correct but I always struggle when interfaces join the story.
Let's deal with "whether or not it compiles" first.
The key to determining this is to look at the compile time type, i.e. the declared type of the variables.
Generally,
Casting from a compile time interface type to an interface type always compiles.
Casting from a compile time interface type to a class only compiles if any of the following is true:
the class is non-final
the class implements the interface
Casting from a compile time class type to an interface type only compiles if any of the following is true:
the class is non-final
the class implements the interface
Casting from a compile time class type to another class type only compiles if one of them inherits from the other class.
To determine whether the cast succeeds at runtime, the key is to look at the runtime type of the object stored in the variable. For example:
A a = new B();
The compile time type of a is A, but the runtime type is B.
Generally, casting from runtime class type T to a class or interface type U only succeeds if T inherits from U or implements U.
For future readers,
If instead you want to know how to check if a cast will succeed using code, you should refer to this question.
First of all, in your scenario the following is not a downcasting at all because in described hierarchy B is B, B is A and B is InterfaceA. So any of these casts can be omitted.
InterfaceA i = (InterfaceA)(A)(B) b;
Then, answering your question. Downcasting will be compilable then and only then when it is possible to be successful in runtime. Let's introduce additional class D, that extends class A and implements InterfaceB1.
A a = new A();
InterfaceB1 b1 = (InterfaceB1) a; // compilable as A reference can contain object of class B that implements InterfaceB1
InterfaceB2 b2 = (InterfaceB2) a; // compilable as A reference can contain object of class B that implements InterfaceB2
b1 = (InterfaceB1) b2; // compilable as InterfaceB2 reference can contain object of class B that implements both InterfaceB1, InterfaceB2
B b = (B) a; // compilable as A reference can contain object of class B
C c = (C) a; // compilable as A reference can contain object of class C
D d = (D) a; // compilable as A reference can contain object of class D
d = (D) b1; // compilable as InterfaceB1 reference can contain object of class D in runtime
b = (B) d; // not compilable since D reference can NEVER contain object of class B in runtime
c = (C) d; // not compilable since D reference can NEVER contain object of class D in runtime
As for causing ClassCastException it is always about what actually is contained in your object reference.
A a1 = new A();
A a2 = new B();
InterfaceB1 b1 = (InterfaceB1) a1; // compiles but causes ClassCastException as A cannot be cast to InterfaceB1
InterfaceB1 b2 = (InterfaceB1) a2; // compiles and runs just normally as B can be cast to InterfaceB1
class A{}
class B extends A {}
class C extends B {}
class D<C> {
C c = new A(); // COMPILER ERROR
}
After type erasure code becomes:
class D {
Object c = new A();
}
So, what's the problem here?
So, what's the problem here?
The first problem is that within D<C>, C refers to the type parameter called, C, not the class C that extends B. Next, even ignoring generics,
C c = new A(); // Invalid
... wouldn't compile... instead, you'd normally have:
A a = new C(); // Normally fine - but not if C is a type parameter!
Suppose you tried using:
D<String> d = new D<String>();
Then you're effectively asking the compiler to consider this line to be valid:
String c = new A();
That's clearly broken.
I have a broad question regarding Java casting via classes. Let's say I create 4 classes (well 3 classes and 1 interface), Interface A is the super interface I guess you could say and Class B implements A (meaning that it is the subclass of the interface A) and C extends B and then D extends C.
Let's say that I have a driver class in which I initialize the following like below:
A myA;
B myB = new B();
C myC = new C();
D myD = new D();
//I want to cast now!
myB = (B) myD;
myC = (D) myA;
myD = (C) myB;
When are these fabricated objects actually compilable? I'm having a bit of a difficult time understanding the rules between casting. I do kind of understand Down-casting and how it's not permitted, but I guess class casting is still a concept that sort of confuses me.
The thumb rule is that if an object B is of type A, then it can be casted to A. In you example B implements A so B is of type A. You can cast any B object to A. Since C extends B, C is of type B as well as of type A. So C objects can be cast to A or B.
Wanted to add as comment, but coz of limitation, had to add it as answer:
1) Rule is Child can inherit what father/parent has, but not reverse.
2) Child can be stored as parent, but not reverse.
That makes myD =(C)myAB; uncompilable as myD extends C (which extends B-->A)
So when you create
B myB = new B();
If I try to explain in non technical terms, Then myB knows everything about B and A, but it does not know what is below. It can see and identify itself with anything above it in following hierarchy:
A
B
C
D
So lowest one D can be casted to anything that lies above it.
1) myB = (B) myD;
With rule state above, D is below B and hence can be assigned to B.
2) myC = (D) myA;
Here you have casted interface to D, and hence in compile time, D can be assigned to top level C.
3) Here myB (which in that statement is typecasted to C in compile time) can't be assigned to D at compile time (although it is instance of D which is lower in hierarchy) but when you are compiling, you don't have runtime instance available. So below will fail:
myD = (C) myB;
I assume I have not confused you further here.
If you have two different classes A and B, and B is a subclass of A, you cannot cast as follows:
A a = new A();
B b = new B();
A newA = (A)b;
Is there a way to enable the above code to work (no alterations to the above code) without the JVM throwing a ClassCastException?
------------EDIT----------
Sorry, I made a mistake in the code in the above question. The correct version is below:
A a = new A();
B b = new B();
B newB = (B)a;
B already has an is-a relationship to A. You don't need to cast it....You can throw a B at any method or reference that expects/points to an A.
Based on your edit -- there is something wrong with your design if you want to do this. While a B is-a A, the opposite is NOT true. An A is not a B. In other words, since B extends A, it probably has methods/properties on it that are NOT defined on A. If you cast an A to a B, then methods that accept that reference might try to invoke a method it believes is on the instance, since you told the compiler that it got a B, when in reality the underlying A does not have the required method.
Casting here will only lead to pain and failure.
I think you can simply assign:
A newA = b;
If B is a subclass of A the above should work, and the cast would be unnecessary:
A a = new A();
B b = new B();
A newA = b; // no need to cast!
With new code, no you can't do that. You'd have to create a new object:
B newB = new B(a);
or
B newB = B.of(a);
A non-abstract non-leaf class should generally be avoided anyway. Also, since 1.5 (released 2004), there shouldn't be much of the casting syntax about.