Reputation: 1223
Skip to the last sentence if you want to read the question right away.
Suppose we have an Interface and three classes:
interface I{}
class A implements I{}
class B extends A {}
And the following declarations:
A a = new A();
B b = new B();
Now, there's the classic way of casting which allows me to cast a reference of type A (the parent class) to an object of type B (the child class) like this:
a = b; //here a is no longer pointing at object A, and is now pointing at the same object b is pointing at.
b = (B) a; // the casting is now accepted by the compiler and during runtime as well.
Here where lies the problem though. Every time I see a line of code with multiple casting, I fail to read it (literally) and, as a result, I can't understand what it means.
For instance, let's say we have this line of code:
a = (B)(I)b;
How would you read this one? a
is a reference to an object of type A, and it is being assigned the value of an object of type B (first cast from the left). But wait a minute, there's also another cast (I) preceding b. So what do we have here? Is it an interface being cast as a (B) object? or is it a b being cast as an interface which is also being cast as a (B)?
I tried to break it down to avoid confusion:
I temp = (I) b;// first line
a = (B) temp;// second line
So, first, since b is an I (because it extends A which implements I), "first line" is accepted by the compiler and during runtime.
"Second line" though, we have a reference to an object A being assigned a value of type B. At first glance, there's nothing wrong with it. But then I realized I
is not an A nor is it a B, and even though the cast in "second line" can dupe the compiler into believing it's an object of type B, it shouldn't be accepted at runtime.
So the main question that I would like an answer to is how do I interpret the following line:
a = (B)(I)b;
Upvotes: 2
Views: 6026
Reputation: 38300
Reality or The answer you don't want
The real problem here is that a careless goofball wrote crappy code. The real solution is; either don't write crappy code or fix the code.
Lets keep being a goofball or The answer you seem to want
There are two types of casting in java; up-casting and down-casting.
Up-casting is when you cast an object of type A to be an instance of interface I; you are casting "up" the inheritance tree. For example:
A aObject = new A();
I iObject = (I)aObject; // Up casting.
The benefit of up-casting is that the compiler is able to determine, at compile time, if the cast is legal.
Down-casting is when you cast an object of type I to be an object of type A; you are casting "down" the inheritance tree. For example:
A aObject;
I iObject = new A();
aObject = (A)iObject;
The compiler does not know, at compile time, if down-casting will succeed. Because of this, a down-cast may throw an exception at runtime.
Your confusing code: a = (B)(I)b;
is an example of both up-casting (safe) and down-casting (not safe).
As a bonus, the casting is in no way required. It is always safe to assign a B object directly to an A reference because the B class extends the A class.
Addressing: "careless goofball" seems like strong language. It is not strong language, it is the nicest way to describe the cause your situation. In truth, somebody who writes code like that should be terminated (optionally, get them hired by one of your competitors).
Upvotes: 8
Reputation: 1891
Maybe you don't get the point that, even if cast to I or A, b remains an Object of type B, it doesn't loose its nature. Think of casting a way to say to java 'see my object as an object of type I'. Then if type B it is also of type A.
So the instruction tells java 'use my object as it is of type I and immediatly after use it as type B, which, by declaration, is also of type A. So no compile or runtime errors.
Then we can see.that it looks also mostly unuseful and ugly..
Upvotes: 0
Reputation: 4786
Based on the Java language grammar, the statement
a = (B)(I)b;
might be better visualized like this:
a =
// outer CastExpression
(B)(
// with its UnaryExpression being another CastExpression
(I)(b)
);
That is, it casts b
to I
, then casts that to B
, then assigns that to an A
variable.
However, it doesn't look like either of these casts are necessary. If b
is an instance of B
, it is also an instance of A
and I
.
Upvotes: 2
Reputation: 73538
a = (B)(I)b;
Cast b
to I
, and then cast it to B
. Presumably since you can't cast b
to B
directly.
Now there aren't really good situations to use this, since casting even a single time should be avoided if possible. However if you want something like
String s = (String) myHashMap;
to compile, you need to upcast to prevent the compiler from disallowing an obviously illegal cast:
String s = (String) (Object) myHashMap;
Naturally if your myHashMap
isn't null, this will cause a runtime ClassCastException
, but unlike the earlier example it will compile.
Upvotes: 0