We convert data from one type to another all the time. If you visit Europe and drive a car, for example, you'll likely convert kilometers per hour to miles per hour in your head to have a better sense of how fast you're going. You'll also be using conversion when you withdraw euros instead of dollars from an ATM there.
The same idea applies to the Java programming language. All data is categorized by type so programs know how to handle it when executing. Depending on what you want a program to do, however, on occasion you'll need to change the category of the data you're using. This doesn't change the data itself – after all, a car travels at an equivalent rate of speed whether it's measured in kilometers or miles per hour – but only how it's being referenced.
What are the data types in Java? How do you change data types? We'll go over all this and more below as we cover what you need to know about type casting in Java.
Java Data Types

There are three basic categories of data in Java:
- True/false
- Text characters
- Numbers
This table breaks out the specific types of data within these categories.
Category Data Type Contains Size
T/F boolean true or false 1 bit
Text char Unicode text character 16 bits
Number byte signed integer 8 bits
Number short signed integer 16 bits
Number int signed integer 32 bits
Number long signed integer 64 bits
Number float IEEE 754 floating point 32 bits
Number double IEEE 754 floating point 64 bits
Any number can be moved from a smaller to larger number size such as an 8-bit byte to a 16-bit short (or more!) with no problem as you're still working with data in the number category. You don't even have to do anything as Java will implicitly perform this conversion.
On the other hand, even though it's moving from a smaller to a larger size, 1-bit boolean data cannot automatically be converted to 16-bit Unicode because these are two different data types. If a program attempts this, an automatic error message will be generated. To avoid this problem, you'll need to explicitly convert these data types within the program you're writing.
Upcasting in Java
The example above recasting a number's data type from a byte to short – that is, from a subclass to a superclass – is also called upcasting. Let's look at how this works by defining a class called Trucks:
public class Trucks {
public void fuel() {
// ...
}
}
After this, we can extend the Trucks class by adding Chevrolet:
public class Chevrolet extends Trucks {
public void fuel() {
// ...
}
public void diesel() {
// ...
}
}
Let's create a Chevrolet class object and assign it the reference variable type Chevrolet:
Chevrolet chevrolet = new Chevrolet();
And we can also assign it to the reference variable of type Trucks:
Trucks trucks = Chevrolet;
With the code above, we do not need to explicitly change the data types because implicit upcasting will occur. If we did explicitly want to do this, here's the code:
Trucks = (trucks) Chevrolet;
Keep in mind: At this point we can’t invoke diesel() on the variable Trucks because we'd receive the following compiler error message:
// trucks.diesel(); The method diesel() is undefined for the type Trucks
We'd need to downcast trucks to invoke diesel, and we'll cover that below. Regarding upcasting, however, now we can utilize polymorphism.
Polymorphism
Polymorphism is when you have different members making up a larger overall group. For example, pennies, dimes, and quarters are different members of the overall group known as currency. In the case of our trucks example, thanks to polytheism, we can add yet another subclass to Trucks called Ford:
public class For extends Trucks {
public void fuel() {
// ...
}
}
After this, let's define the fuel() method to categorize Chevrolets and Fords as trucks:
public class TruckGas {
public void feed(List<Truck> trucks) {
trucks.forEach(truck -> {
truck.fuel();
});
}
}
TruckGas isn't concerned with either Chevrolets or Fords in particular as trucks – and all the objects associated with it – will now be in the fuel() method.
When we add specific types of objects to the truck list, upcasting implicitly takes place:
List<Trucks> trucks = new ArrayList<>();
trucks.add(new Chevrolet());
trucks.add(new Ford());
new TruckGas().fuel(trucks)
Thanks to polymorphism, every Chevrolet and Ford is a truck.
Overriding
In the code above, the fuel() method has been overridden. While fuel() is called on the variable of the Trucks type, the work is performed by methods invoked on the actual objects Chevrolets and Fords:
public void feed(List<Truck> trucks) {
trucks.forEach(truck -> {
truck.fuel();
});
}
We can see what the methods for both Chevrolets and Fords are called if we add logging:
web - 2018-07-23 08:43:37,354 [main] INFO com.javabeat.casting.Chevrolet - chevrolet is fueling
web - 2018-07-23 08:43:37,363 [main] INFO com.javabeat.casting.Ford - ford is fueling
Downcasting in Java
Unlike upcasting where a subclass is cast as a superclass, downcasting is the opposite action: casting a superclass as a subclass. And, while a compiler will implicitly upcast, we'll have to write code to explicitly downcast. Let’s take a look at this example:
Truck truck = new Chevrolet();
The truck variable refers to the instance of Chevrolet. So, let’s say we need to invoke Chevrolet's diesel() method on truck. The compiler, however, will generate an error message saying the diesel() method doesn’t exist for the type Truck. This means we must downcast truck to Chevrolet to call diesel:
((Chevrolet) truck).diesel();
Now, we'll rewrite the earlier TruckGas example with the diesel() method:
public class TruckGas {
public void feed(List<Truck> trucks) {
trucks.forEach(truck -> {
truck.fuel();
if (truck instanceof Chevrolet) {
((Chevrolet) truck).diesel();
}
});
}
}
At this point, we're able to gain access to all methods available to the Chevrolet class. We can check the log to make sure diesel() is actually called:
web - 2018-07-23 10:12:33,445 [main] INFO com.javabeat.casting.Chevrolet - chevrolet is fueling
web - 2018-07-23 10:12:33,454 [main] INFO com.javabeat.casting.Chevrolet - diesel
web - 2018-07-23 10:12:33,455 [main] INFO com.javabeat.casting.Ford - ford is fueling
instanceof Operator
You'll note in the example above we only downcast objects which are instances of Chevrolet. That's why we used the operator instanceof to do this:
if (truck instanceof Chevrolet) {
((Chevrolet) truck).diesel();
}
Cast() Method
Finally, we can also use the Class methods to cast object types:
public void whenDowncastToChevroletWithCastMethod_thenDieselIsCalled() {
Truck truck = new Chevrolet();
if (Truck.class.isInstance(truck)) {
Chevrolet chevrolet = Chevreolet.class.cast(truck);
chevrolet.diesel();
}
}
In the code above, as opposed to using cast and instanceof operators, cast() and isInstance() methods are utilized. This is most commonly done when using generic types.
Additional Type Casting in Java Resources
While we've gone over the basics of type casting in Java, there are more ins and outs to all this you'll want to be familiar with. One benefit of Java being open source is that there are plenty of reference sites and tutorials available. Given that, you should check out these free Java-related resources.
Oracle
The first place to begin is with the Java documentation available at the Oracle website. In particular, you'll want to take a look at Chapter 5: Conversions and Contexts. This information dives even deeper into the specific conventions and uses of casting and identity conversion:
- widening and narrowing primitive conversions
- widening and narrowing reference conversions
- boxing conversion
- unboxing conversion
- unchecked conversion
- capture conversion
- string conversion
- value set conversion
- forbidden conversions
Plus, you'll learn about the various contexts where all these conversions operate: assignment, invocation, string, casting, and numeric.
Wideskills
In this detailed Java Object Typecasting tutorial, you'll walk through both upcasting and downcasting via detailed screenshots and examples of code. Plus, the ClassCastException error message and how to avoid it are discussed at length. You also have the option to download all the source code used as examples.
There is a wide range of other coding-related tutorials at the Wideskills site beyond the twenty covering Java. Additional subject areas include Microsoft programming, mobile device programing, databases, and more.
fresh2refresh
A wide variety of topics are covered in this in-depth Java – Type Conversion and Casting tutorial: primitive and reference data types, arithmetic promotion, assignment conversion, and method invocation conversion. In addition, you can access an online Java compiler as well as other compilers such as C, C++, C#, Python, and Ruby.
You might also look at the other subject areas with tutorials: SQL, Unix, XML, C++, C, and JSP. The XML tutorial series, for example, covers twelve different topics such as document type definitions (DTDs), entities, and XLinks and XPointers.
Both upcasting and downcasting are powerful operations within Java you'll need to thoroughly understand to avoid compiler error messages. Remember: While upcasting is done automatically – that is, implicitly – by the compiler, you'll need to write code to explicitly downcast data types and generate the correct output.