Let's get started with a Microservice Architecture with Spring Cloud:
Explanation of ClassCastException in Java
Last updated: September 6, 2026
1. Overview
In this short tutorial, we’ll focus on ClassCastException, a common Java exception.
ClassCastException is an unchecked exception that signals the code has attempted to cast a reference to a type of which it’s not a subtype.
Let’s look at some scenarios that lead to this exception being thrown and how we can avoid them.
2. Explicit Casting
For our next experiments, let’s consider the following classes:
public interface Animal {
String getName();
}
public class Mammal implements Animal {
@Override
public String getName() {
return "Mammal";
}
}
public class Amphibian implements Animal {
@Override
public String getName() {
return "Amphibian";
}
}
public class Frog extends Amphibian {
@Override
public String getName() {
return super.getName() + ": Frog";
}
}
2.1. Casting Classes
By far, the most common scenario for encountering a ClassCastException is explicitly casting to an incompatible type.
For example, let’s try to cast a Frog to a Mammal:
Frog frog = new Frog();
Mammal mammal = (Mammal) frog;
We might expect a ClassCastException here, but in fact, we get a compilation error: “incompatible types: Frog cannot be converted to Mammal”. However, the situation changes when we use the common super-type:
Animal animal = new Frog();
Mammal mammal = (Mammal) animal;
Now, we get a ClassCastException from the second line:
Exception in thread "main" java.lang.ClassCastException: class Frog cannot be cast to class Mammal (Frog and Mammal are in unnamed module of loader 'app')
at Main.main(Main.java:9)
A checked downcast to Mammal is incompatible from a Frog reference because Frog is not a subtype of Mammal. In this case, the compiler cannot help us, as the Animal variable may hold a reference of a compatible type.
It’s interesting to note that the compilation error only occurs when we attempt to cast to an unequivocally incompatible class. The same is not true for interfaces because Java supports multiple interface inheritance, but only single inheritance for classes. Thus, the compiler can’t determine if the reference type implements a specific interface or not. Let’s exemplify:
Animal animal = new Frog();
Serializable serial = (Serializable) animal;
We get a ClassCastException on the second line instead of a compilation error:
Exception in thread "main" java.lang.ClassCastException: class Frog cannot be cast to class java.io.Serializable (Frog is in unnamed module of loader 'app'; java.io.Serializable is in module java.base of loader 'bootstrap')
at Main.main(Main.java:11)
2.2. Casting Arrays
We’ve seen how classes handle casting, now let’s look at arrays. Array casting works the same as class casting. However, we might get confused by autoboxing and type-promotion, or lack thereof.
Thus, let’s see what happens for primitive arrays when we attempt the following cast:
Object primitives = new int[1];
Integer[] integers = (Integer[]) primitives;
The second line throws a ClassCastException as autoboxing doesn’t work for arrays.
How about type promotion? Let’s try the following:
Object primitives = new int[1];
long[] longs = (long[]) primitives;
We also get a ClassCastException because the type promotion doesn’t work for entire arrays.
2.3. Casting Between Numeric Wrapper Classes
Another frequent source of ClassCastException is casting between the numeric wrapper classes. Although int can be cast to long without any effort on our part, the same is not true for Integer and Long. A direct cast between the two doesn’t compile:
Long id = 42L;
Integer count = (Integer) id;
Much like the Frog to Mammal cast we saw earlier, the compiler rejects this outright: “incompatible types: Long cannot be converted to Integer”. Even though Long and Integer both extend Number, they’re siblings in the type hierarchy rather than a parent and a child. As a result, neither one is a subtype of the other, and casting between them fails.
We can encounter this failure even when our code compiles. Let’s consider a scenario where the actual value is read typed as an Object from a JDBC ResultSet, a JSON document, or a plain Map:
Map<String, Object> row = new HashMap<>();
row.put("count", 42);
Long count = (Long) row.get("count");
Here, our code compiles, but we get a ClassCastException at runtime:
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.Long (java.lang.Integer and java.lang.Long are in module java.base of loader 'bootstrap')
at Main.main(Main.java:6)
The solution to this is to convert the values instead of casting. As we noted earlier, both the wrapper classes extend Number, which exposes methods like intValue(), longValue(), doubleValue(), etc. Let’s use it to fix both of our examples:
Long id = 42L;
Integer count = id.intValue();
Map<String, Object> row = new HashMap<>();
row.put("count", 42);
Long count = ((Integer) row.get("count")).longValue();
Here, we call the intValue() method directly on the Long reference in the first example, since the compiler already knows its exact type. In the second example, we first cast the value to Integer, which is its real runtime type, and only then call the longValue() method to get the number we actually want. Both conversions return a primitive, which Java autoboxes back into the wrapper class we’ve declared.
It’s important to remember that when we don’t know the exact runtime type beforehand, we can cast to the Number class rather than to a specific wrapper. Since every numeric wrapper extends it, the cast succeeds, and we can then call desired method on the result.
2.4. Safe Casting
In the case of explicit casting, it is highly recommended to check the compatibility of the types before attempting to cast using instanceof.
Let’s look at a safe cast example:
Mammal mammal;
if (animal instanceof Mammal) {
mammal = (Mammal) animal;
} else {
// handle exceptional case
}
3. Heap Pollution
As per the Java Specification: “Heap pollution can only occur if the program performed some operation involving a raw type that would give rise to a compile-time unchecked warning”.
For our experiment, let’s consider the following generic class:
public static class Box<T> {
private T content;
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
}
We will now attempt to pollute the heap as follows:
Box<Long> originalBox = new Box<>();
Box raw = originalBox;
raw.setContent(2.5);
Box<Long> bound = (Box<Long>) raw;
Long content = bound.getContent();
The last line will throw a ClassCastException as it cannot transform a Double reference to Long.
4. Generic Types
When using generics in Java, we must be wary of type erasure, which can lead to ClassCastException as well in some conditions.
Let’s consider the following generic method:
public static <T> T convertInstanceOfObject(Object o) {
try {
return (T) o;
} catch (ClassCastException e) {
return null;
}
}
And now let’s call it:
String shouldBeNull = convertInstanceOfObject(123);
At first look, we can reasonably expect a null reference returned from the catch block. However, at runtime, due to type erasure, the parameter is cast to Object instead of String. Thus the compiler is faced with the task of assigning an Integer to String, which throws ClassCastException.
5. Conclusion
In this article, we have looked at a series of common scenarios for inappropriate casting.
Whether implicit or explicit, casting Java references to another type can lead to ClassCastException unless the target type is the same or a descendent of the actual type.
The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
















