Upcasting and Downcasting in Java
Type casting in Java is an important and very interesting topic to deal with. But here upcasting and downcasting is somewhat related to typecasting. In normal typecasting, we convert from one data type to another data type implicitly or explicitly. Here we do typecast for objects. And yes, just like datatypes, the objects can also be typecasted.
This topic is completely related to “Inheritance”. Where we just have parent objects as well as child objects. Typecasting is done in two types i.e., from parent to child or from child to parent.
The casting of a child object to a parent object is known as upcasting. The reverse of this is known as downcasting.

( Diagrammatic representation of upcasting and downcasting in Java )
Upcasting :
It is a type of object-type casting. Here child object is type cast to the parent object. The child class object is assigned to the parent class reference variable. It is also known as “Generalization” or “Widening”.
For example:
// Upcastingexmpl.java
class father{ // parent class
void says(){System.out.println("Hi ! I am a father");
}
}
class daughter extends father{ // child class
void says(){ // method overriding
System.out.println("Hi ! I am daughter");
}
}
class Upcastingexmpl{
public static void main(String args[]){
father f = (father) new daughter(); // implicit upcasting
f.says();
}
}
Output:

Downcasting
It is another type of object typecasting. It is also known as "Specialization" and "Narrowing". It is reverse to upcasting. The parent object should be assigned to the child reference variable i.e., the parent object is typecasted to the child object.
For example:
Downcastingexmpl.java
class father{ // parent class
void says(){
System.out.println("Hi ! I am father");
}
}
class daughter extends father{ // child class
void says(){ // method overriding
System.out.println("Hi ! I am daughter");
}
}
class Downcastingexmpl{
public static void main(String args[]){ // explicitly doing downcasting
daughter d = (daughter) new father(); // compile time error
d.says();
}
}
Output:

Here we aregetting run time error. Is downcasting not supported in java? Did this question raise in your mind? The answer is yes. Java supports downcasting but through some other methods. Downcasting is performed by assigning subclass objects to the child class.
For example:
Downcasting.java
class father { // parent class
String name; // local variable
void says()
{
System.out.println("Hi ! I am father");
}
}
class daughter extends father { // Child class
int age; // local variable
void says()
{
System.out.println("Hi ! I am daughter");
}
}
public class Downcasting{
public static void main(String[] args)
{
father f = new daughter();
f.name = "xyz";
daughter d = (daughter) f; // downcasting explicitily
d.age = 18;
System.out.println(d.name);
System.out.println(d.age);
d.says();
}
}
Output:

“Upcasting can be done implicitly. Whereas downcasting cannot be done implicitly.”
Let's consider a real-world example, Parents have many children. Let us consider one child currently. The child inherits all the properties of the parent. So, the child can be implicitly upcasted to the parent. However, the parent cannot inherit the child's properties. But parents can forcefully inherit a child's properties which is known as downcasting which is explicit i.e. not implicit.
Rules of object type casting
The syntax for typecasting is
A b = ( C ) d
Here we are converting the d type object to C type. Now the d will become C type. And now we are assigning this C type object to A type reference variable. In this typecasting compiler is going to check two rules and JVM (Java Virtual machine) is going to check one rule.
What compiler is going to check?
Compile time checking 1 or Rule 1: Whether conversion of “d” type into “C” type is legal or not?
How the compiler checks are, the type of "d" and "C" must have some relationship i.e., either parent to child or child to parent or both are of the same type.
If there is no relationship, then we are going to get “compile time error” like incompatible types, etc…
Example to check rule 1:
// Test.java
class Test{
public static void main(String args[]){
Object o = new String("Deekshitha");
StringBuffer sb = (StringBuffer)o; // downcasting explicitly
// we have a relationship between object and string buffer
}
}
To check rule 1 satisfies or not we should compile it.
Output:

Example 2:
Test.java
class Test{
public static void main(String args[]){
String s = new String("Deekshitha");
StringBuffer sb = (StringBuffer)s; // compile time error as there is no relation between string and string buffer
}
}
Output:

Here we are getting compile time error i.e., incompatible types.
Once rule 1 is valid then the compiler checks for rule 2.
Compile time checking 2 or Rule 2: Is assigning the "C" type to the "A” reference variable legal or not?
How the compiler checks are, "C" must be either same as "A" or "A's" child type. If this condition is satisfied, then the code is going to compile.
To check rule 2 is satisfying or not let us consider the above code only. There rule 1 is satisfied. “o” is converted into string buffer type. And string buffer type is assigned to the string buffer reference variable only. Therefore, we can notice the relationship, hence rule 2 is satisfied.
Another example:
String s = new String(“Deekshitha”) ;
StringBuffer sb = (String)s;
Here s is of string type. And s is assigned to the String Buffer reference variable. There is no relation between String and String Buffer. Hence, we will get compile time error.
Example:
Test2.java
class Test2{
public static void main(String args[]){
String s = new String("Deekshitha");
StringBuffer sb = (String)s; // compile time error as there is no relation between string and string buffer.
}
}
Output:

What JVM ( Java Virtual Machine ) Is going to check?
JVM rule :
The internal runtime object type of "d" must be either same as "C" or as its child type. Otherwise, we will get a run time exception.
You might be wondering what is runtime object. Let's understand with an example.
Object 0 = new String(“Deekshitha”);
StringBuffer sb = (StringBuffer)o;
Here "o" is the object type. But internally this object type is pointing to a String object. So, the original run time object is a String object.
So, the original run time object " String " must be either the same or derived type of " C " i.e., here StringBuffer. Here String is not the same as String Buffer or not a derived class of String Buffer. Therefore, immediately we will get a run time exception saying class cast exception.
Example :
Test2.java
class Test2{
public static void main(String args[]){
Object o = new String("Deekshitha"); // instance reference variable of object
StringBuffer sb = (StringBuffer)o; // run time error as instance reference variable and string buffer have no relation.
}
}
Output :

Example 2:
Test3.java
class Test3{
public static void main(String args[]){
Object o = new String("Deekshitha"); // instance reference variable
String s = (String)o; // assigning instance reference variable to string reference variable
}
}
Output:

Example 3:
Test3.java
class Test3{
public static void main(String args[]){
Object o = new String("Deekshitha");
String s = (String)o; // downcasting explicitily
System.out.println(s); // getting s value
}
}
Output:

Upcasting Vs. Downcasting
Upcasting | Downcasting |
Here a child object is a type cast to the parent object. | Here a parent object is a type cast to a child object. |
It is done implicitly or explicitly. | It is done explicitly only. |
It is also known as generalization or widening. | It is also known as specialization or narrowing. |
In child class, some specialized methods can be accessed through upcasting. | Through down casting, we can access all the methods and variables of both classes. |
Syntax : Parent p = new child ( ) ; | Syntax : Parent p = new child ( ) Child c = ( child ) p; |