In this tutorial, we’ll be discussing typecasting and its various forms in Java. Let’s get started.
Type Casting in Java
In simple terms, type casting means converting the type of a primitive/reference variable. We’ll be dealing with three types of scenarios in typecasting:
- Primitive types
- Object types
- Wrapper Classes and primitives
Hence, this tutorial would be divided into three parts:
- Widening and Narrowing
- Upcasting and Downcasting
- Autoboxing and Unboxing
Just for the sake of simplicity and in order to differentiate the primitive and reference type examples we are using different terms.
Let’s get started!
1. Widening and Narrowing Type casting
Widening means a small type can be accommodated in a larger type without any loss of information.
Widening Typecasting is automatic.
That means a byte value can be automatically casted to short, int, long or double.
Widens from left to right.
boolean types cannot be cast to anything else. They are always true or false.
Example:

Jshell Wide Type Casting
Let’s look at another example:

Jshell Type Casting Error
As you can see, wide to narrow typecasting automatically would lead to a compile-time error.
For that, we need to do explicit type casting as:

Jshell Narrow Type Casting
This is narrow typecasting and must be done manually.
2. Upcasting and Downcasting
In simple words :
Upcasting is casting from a subclass to a superclass.
Downcasting is casting from a superclass to a subclass.
Upcasting happens automatically and we do not have to do anything explicitly.
Downcasting if done implicitly can cause a compiler error.
In the following examples, our inheritance tree would like :
JournalDev -> Java -> Android
// Base Class
class JD
{
public void printMe() { System.out.println("JournalDev print method"); }
}
// Inherited class
class Java extends JD
{
public void printMe() { System.out.println("Java print method"); }
}
// Inherited class
class Android extends Java
{
public void printMe() { System.out.println("Android print method"); }
}
class Main
{
public static void main(String[] args)
{
JD jd = new Java();
jd.printMe(); //prints Java print method
}
}
The above case is an example of upcasting.
Let’s use the same concept on downcasting and see what happens:
Android android = new Java();
This will cause a compile-time error.
Use the following instead:
Java java = new Android();
Android and = (Android) java;
Let’s say we have a class like:
class JavaEE extends Java
{
public void printMe() { System.out.println("JavaEE print method"); }
}
Now:
Java java = new Android();
JavaEE javaEE = (JavaEE)java; //classcastexception
To tackle such cases, use instanceof
operator before typecasting.
Downcasting is typically used when we want to access specific behaviors of subtype.
3. AutoBoxing and unboxing
If we want to use primitive types as reference objects, we can use their equivalent wrapper classes.
Example: int has Integer and so on…
Autoboxing refers to automatically converting a primitive type to a reference type.
Example:
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
Here we added a primitive type to a reference type by automatically boxing it.
Unboxing means converting an object of a wrapper type to its corresponding primitive value For example conversion of Integer to int
To explicitly unbox we can use the built-in methods such as intValue(), floatValue() and so on:
Integer obj = new Integer("123");
int i = obj.intValue();
System.out.println(i); //123
That brings an end to this tutorial on Type casting in Java.
for example of Upcasting and downcasting, please change new Child(); to new Java();
Actually when we need to use upcasting in real projects?
Whenever possible we should refer to a more abstract level of class. Hence in such cases upcasting is a good practice.
Otherwise, no obvious use cases.