[ACCEPTED]-Question about Java polymorphism and casting-polymorphism

Accepted answer
Score: 18

Consider a real-world example:

public class Dog extends Animal

All dogs are 37 animals, but not all animals are dogs. Hence...

public class Cat extends Animal

Casting 36 an Animal to a Dog can only be done if the 35 Animal in question is indeed a Dog. Otherwise 34 it would force the Universe to infer properties 33 unique to a dog (wagging tail, barking, etc.) onto 32 an Animal. That Animal might well be a Cat 31 with properties unique to it (purring, rigorous 30 regime of self-cleaning, etc.). If the cast 29 is not possible then a ClassCastException 28 is thrown at runtime.

Nobody wants a dog 27 that purrs.

((M) k).getClass() gives K. Why 26 is that? It was casted to the more general 25 M!

You've casted k to M, but all classes 24 have a getClass() method. k's class is always 23 K, regardless of whather you cast its reference 22 to M or not. If you cast a Dog to an Animal 21 and ask it what animal it is it'll still 20 answer that it's a dog.

In fact, casting 19 to a superclass is redundant. A Dog already 18 is an Animal and it has all the methods 17 of an Animal as well as its own. Many Code 16 Analysis tools such as FindBugs will notify 15 you of redundant casts so you can remove 14 them.

Suppose I have a doIt() method implemented 13 in both M and K. executing

((M) k).doIt();

gives 12 M's or K's doIt()?

K's doIt() for the same 11 reasons as above. The cast operates on the 10 reference; it doesn't transform an object 9 to a different type.

Can you give an example 8 of when casting (Dog doggy = (Dog) myAnimal) makes 7 sense?

Sure can. Imagine a method that receives 6 a list of animals for processing. All the 5 dogs need to be taken for a walk, and all 4 the cats need to be played with using a 3 bird-shaped toy. To do this we call the 2 takeForWalk() method that only exists on Dog, or the 1 play() method which only exists on Cat.

public void amuseAnimals( List<Animal> animals ) {
    for ( Animal animal : animals ) {
         if ( animal instanceof Dog ) {
             Dog doggy = (Dog)animal;
             doggy.takeForWalk( new WalkingRoute() );
         } else if ( animal instanceof Cat ) {
             Cat puss = (Cat)animal;
             puss.play( new BirdShapedToy() );
Score: 8

You can't cast objects in Java.

You can cast 7 references in Java.

Casting a reference doesn't 6 change anything about the object it refers 5 to. It only produces a reference of a different 4 type pointing to the same object as the 3 initial reference.

Casting primitive values 2 is different from casting references. In 1 this case the values do change.

Score: 7

Just because E extends C, C doesn't become 26 an E... E on the other hand is a C

Edit: To expand 25 Mark's comment below... Just because every 24 woman is a human, not all humans are women. All 23 humans share the "human interface" with 22 legs, hands, faces, etc. Women extends it 21 with functionality that returns good feelings 20 when you provide diamonds and gold.

The int 19 => double conversion is not even related 18 as it is not a class cast but a conversion 17 telling the compiler to store whatever is 16 in x in y (which happens to be a double).

((M) k).getClass() gives 15 K.

because k is still a K even if you cast 14 it to an M or an Object (or something else 13 it happens to be).

Edit: I think the confusion 12 here is because you consider k to "become" an 11 M when you cast it, it doesn't. You are 10 just treating it as an M. If you ask someone 9 who is a "dog owner" what kind of breed 8 it is he will not return "It's a dog", the 7 reason is simply that the getBreedName() method 6 is likely to have been overridden in the 5 subclass LabradorOwner to return "Labrador". It 4 is the same with getClass(), it will return 3 the class of the implementation. It will 2 not be an M but a K that happens to be an 1 M as well just because K extends M.

Score: 4

the int/double is unrelated; that is a conversion, not 21 a cast - there is no relationship between 20 int and double.

Re the question; a type's object is 19 fixed at creation. An object that is a C is not (and 18 can never be) an E. However, you can treat an 17 E as a C, since inheritance represents "is 16 a". For example:

E e = new E();
C c = e;

Here we still only have 15 one object - simply that the c variable thinks 14 of it as a C, so won't expose methods specific 13 to E (even though the object is an E).

If we 12 then add:

E secondE = (E) c;

This is a type check; again, we 11 haven't changed the object, but to put c into 10 an E variable requires us to prove to the 9 compiler/runtime that it really is an E. We didn't 8 need this in the first example as it can 7 already prove that any E is also a C.

Likewise, with 6 the getClass() - all the cast does is change how the 5 compiler thinks of the object; you haven't 4 changes the object itself. It is still a 3 K.

You need to separate variables from objects. The cast is 2 talking about the variables; they don't change the 1 object.

Score: 1

To add to Frederik's answer, casting an 6 object to something doesn't change it's 5 type. Also, object's can only be cast to 4 a type it already is (the compiler just 3 doesn't know at that point) That's why impossible 2 casts will never be accepted:

Integer i = (Integer) new String();

will not compile, because 1 the compiler knows it can't be possible.

Score: 1

((M) k).getClass() gives K. Why is that? It 21 was casted to the more general M!

A useful 20 analogy (that I got from Bill Venners' site 19 artima.com) that may help clear the confusion 18 is that the difference between classes and 17 objects is like the difference between an 16 architect's blueprint and the actual house 15 that is built. The blueprint exists on paper 14 and is a concept, while the house exists 13 in real life. You can have more than one 12 house built to the same blueprint.

How is 11 that relevant to this question? Let's say 10 there's a McMansion blueprint and a McMansionWithHeatedPool blueprint. A 9 McMansionWithHeatedPool is an extension of a McMansion with a heated pool.

Now, if 8 you see a real McMansionWithHeatedPool, for that object:

  1. Conceptually 7 (i.e., if you look at the architect's blueprints), you 6 would see that a McMansionWithHeatedPool is clearly also a McMansion. Hence 5 the upcast is allowed. (For the same reason, a 4 McMansion object cannot be type cast into a McMansionWithHeatedPool : no 3 heated pool!)

  2. ((McMansion) k).getClass() gives McMansionWithHeatedPool because 2 k is still a McMansionWithHeatedPool. The type cast is on the expression, not 1 on the object.

Score: 1

"If the compiler treats it as an M, it should 10 execute M's methods."
The compiler treats 9 the reference as M. The instance that the reference points 8 to is of type K, not M. You can't cast the 7 reference and assume that means the instance 6 will suddenly change behavior. What the 5 compiler does is make sure that the method 4 you invoke on the specified reference exists. It 3 does not have anything to do with which 2 implementation is invoked, only that an 1 implementation does exist.

Score: 0

For the first question, you cannot cast 8 a superclass to a subclass because a subclass 7 adds members that the superclass doesn't 6 have. How is the compiler supposed to know 5 what values to put there when it's casting? Basically, an 4 E is a C, but a C is not an E.

getClass() gets 3 the type of the object in memory. Casting 2 to M simply hides the fact that it's a K, it 1 doesn't change the underlying object.

Score: 0

Casting an object does not change the object 7 to the object being cast, but allows another 6 class reference that is related to it by 5 inheritance to refer to the object.

For example 4 C extends E. And they both have a method myName();. If you say

E e = new C();

you 3 are calling C myName() method and if you also say

E e = new E();
C c = (C)e;

you 2 just told the compiler that it should allow 1 you refer to E with C reference type.

More Related questions