Remember, there are 2 different things.
1- Reference variable: Used to point / refer to Objects.
2- Object: Instance of a class.
Both have types. So there is the type of a ref. variable and the type of an object.
Before going to explanation lets make some classes:
class Vehicle{}
class Car extends Vehicle{}
class SportsCar extends Car{}
Now lets try to answer the following important question.
What type of objects can a certain type of reference variable refer to?
I will answer this with the words of K&B book. "A reference variable can refer to any object of the same type as the declared reference, or—this is the big one—it can refer to any subtype of the declared type!" (page 99, point 4). Also in case of interfaces, "If the variable is declared as an interface type, it can reference any object of any class that implements the interface." (page 99, point 5)
So if reference variable can refer to objects of subtype then remember that they can NEVER refer to objects of supertypes of the declared type. And this is the most important thing to remember when using casting. We will call this the "Super Rule"
So,
Vehicle v = new Car(); // LEGAL reference variable v referring to a subtype
Car c = new Vehicle(); // ILLEGAL reference variable c can NEVER refer to the supertype Vehicle
Before we move to Casting, Burn this in your mind that reference variables can NEVER refer to objects of supertypes of the declared type.
Reference Variable Casting
Key Points to remember while preforming casting:
A reference variable can be assigned any other ref. variable if its type is a subtype of the declared type, implicitly. This is upcasting i.e.
Vehicle v = null;
Car c = null;
v= c; // can be assigned without casting
A reference variable can be assigned any other ref. variable if its type is a supertype of the declared type, BUT explicitly. This is downcasting i.e.
Vehicle v = null;
Car c = null;
c=(Car)v; // can be assigned by down casting
The Super Rule: Reference variable can refer to objects of subtype and they can NEVER refer to objects of supertypes of the declared type.At compile-time compiler only KNOWS the ref. variable type and NOT what type of object the variable is referring to. At runtime the JVM knows the type of the object that the variable is referring to.
Lets use the above points in the below examples:
#1
compilation: Suceeds. As the reference variable 'v1' is assigned another reference variable 'c' without using any casting. 'c' ref. variable's type is subtype of the 'v1'. No casting required.
Runtime behaviour: Suceeds. As the reference variable 'v1' will be referring to the object in reference variable 'c' which is of type Car (This was assigned at line 2)
Casting Type: Upcasting
#2
compilation: Fails. As the reference variable 'c1' is assigned another reference variable 'v1' without using any casting. 'v1' ref. variable's type is supertype of 'c1'. This requires explicit Casting to compile.
Runtime behaviour: N/A. Didn't compile
Casting Type: downcasting. Must be explicit
#3
compilation: Suceeds. As the reference variable 'c2' is assigned another reference variable 'v1' USING explicit casting as it is required because 'v1' ref. variable's type is supertype of 'c1'.
Runtime behaviour: Suceeds. As the reference variable 'c2' will be referring to the object in reference variable 'v1' which is of type Car (This was assigned at line 5). Based on Super Rule this is OK by JVM
Casting Type: downcasting. Must be explicit
#4
compilation: Suceeds. As the reference variable 'c3' is assigned another reference variable 'v' USING explicit casting as it is required because 'v' ref. variable's type is supertype of 'c3'.
Runtime behaviour: Fails. As the reference variable 'c3' will be referring to the object in reference variable 'v' which is of type Vehicle. At runtime JVM knows the type of the object in ref. variable 'v' and the Super Rule kicks in which is that a ref. variable can't refer to a supertype.
Casting Type: downcasting.
#5
compilation: Suceeds. As the reference variable 'o' is assigned another reference variable 's' without any casting because 's' ref. variable's type is subtype of the 'o'.
Runtime behaviour:Suceeds. As the reference variable 'o' will be referring to the object in reference variable 's' which is of type String (a subtype of Object). This is acceptable by JVM according to Super Rule
Casting Type: upcasting.
#6
compilation: Suceeds. As the reference variable 'c5' is assigned another reference variable 'o' USING explicit casting as it is required because 'o' ref. variable's type is supertype of 'c5'.
Runtime behaviour: Fails. As the reference variable 'c5' will be referring to the object in reference variable 'o' which is of type String. At runtime JVM knows the type of the object in ref. variable 'o' and the Super Rule kicks in which is that a ref. variable can't refer to a supertype.
Casting Type: downcasting.
When to use Downcasting?
There are many situations where you might use downcasting. This all depends on the design and the solution of the problem your are working on. The example in K&B Book is very good. You will come to understand the importance and usage of this concept as your experience in software development increases.
Also in k&B book once you come to the Collections and Generics chapter, will see some usage of downcasting.
One of the places where you need downcasting is when you override equals(Object o) method!
I hope this helps.