Think of it with the "is a" relationship.
Assume C extends B, which extends A.
An object of type C "is a" B. An object of type B "is a" A. Through transitivity, an object of type C "is a" A. In a more concrete example, image you have classes Animal and Cat. A Car "is a" Animal. Now, let's look at that in code:
All of these are examples of "upcasting," or casting to a higher level. In such a case, a cast in never required as the conversion can be done implicitly. Of course, the cast is allowed, it just isn't required.
Now, let's turn this around and look at casting down the tree or "downcasting." We said earlier that an object of type C "is a" A. But, what about the other way around. Can we say, an object of type A "is a" C? NO! That's not true. That's not more true than saying an Animal "is a" Cat. It might be a cat but, more than likely, it's something else, like a
cow or a dog or something else.
Since the animal "might be" a cat, we need to tell the compiler explicitly that it is a cat, or it will yell at us. Let's look at the code:
In this case, the compiler will complain. The object referenced by animal is not, necessarily, a cat. In order to get around this, you must provide a cast:
In such a case, you're basically telling the compiler to trust you in that the object referenced my animal really is a cat. In this siutation, this is true. However, if the variable animal referenced an Animal object, like in the following example, your code would compile, but you'd get a run-time exception:
I hope that helps clear this issue up for you,
Corey