ClassCastException appears when Java is asked to treat a live object as a type it is not. The compiler may accept the cast because the variable type looks compatible, but the JVM checks the real object at runtime and rejects the cast if the concrete class does not match.
You usually meet it when raw collections hide mixed values, when deserialized payloads are read as the wrong type, or when code assumes that every Animal reference can become any subclass the caller wants.
The safest mental model is simple: the declared type tells the compiler what might be valid, but the runtime type tells the JVM what is actually sitting in memory.
A cast is a request to treat a reference as a more specific type. If the object already is that type or a subclass of it, the cast succeeds. If not, the JVM throws ClassCastException at the cast line.
That runtime check is why Object can hold almost anything while still failing later when the caller guesses the wrong subtype.
Raw lists and maps are the classic source. They let mixed values in, and the later read path assumes a specific type that is no longer guaranteed. Deserialization and reflection create the same problem when the code assumes the payload is one class but the data actually carries another.
Inheritance can also mislead people. A Dog reference is an Animal, but an Animal variable that happens to point to a Dog is not a Cat just because the code wants it to be one.
Use instanceof before downcasting, or better, prevent the bad cast entirely by keeping the container typed with generics. If the code is already on Java 16 or newer, pattern matching lets you check and bind in one expression.
For reflection-heavy APIs, use Class.cast() or a typed helper so the boundary where the data enters the system becomes the place where the type is verified.
Print value.getClass().getName() just before the cast. That tells you what the JVM is actually seeing. If the cast came from a collection or a map, trace the write path first because the bad cast is often only a symptom of an earlier bad insertion.
If a helper method keeps returning the wrong runtime type, the bug is usually in that helper, not in the cast line that fails later.
Object payload = "A-42";\n\n// ❌ Wrong assumption: this is not an Integer\nInteger orderId = (Integer) payload;\n\n// ✅ Check the runtime type before casting\nif (payload instanceof Integer id) {\n System.out.println(id + 1);\n} else {\n System.out.println("Order id is stored as " + payload.getClass().getSimpleName());\n}\n\n// ✅ If you expect text, read it as text\nString code = (String) payload;\nSystem.out.println(code.toLowerCase());
List values = new ArrayList();\nvalues.add("harbor");\nvalues.add(12);\n\n// ❌ Runtime cast fails because the first item is a String\nInteger count = (Integer) values.get(0);\n\n// ✅ Type-safe version\nList<Integer> counts = new ArrayList<>();\ncounts.add(12);\nInteger safeCount = counts.get(0);
Map<String, Object> profile = new HashMap<>();\nprofile.put("tier", "gold");\nprofile.put("visits", 8);\n\nObject tier = profile.get("tier");\nif (tier instanceof String label) {\n System.out.println(label.toUpperCase());\n}\n\nObject visits = profile.get("visits");\nif (visits instanceof Integer totalVisits) {\n System.out.println(totalVisits + 1);\n}
Assuming an Object reference can always be cast to the type you want.
Check the runtime type first or redesign the code so the cast is unnecessary.
Using raw collections and casting the retrieved value later.
Parameterize the collection so the compiler enforces the element type for you.
Catching ClassCastException as a normal control flow path.
Validate the type before the cast or change the API contract.
It's thrown when you try to cast an object to a type it's not an instance of. For example, casting a String to Integer, or a Dog to Cat when they don't share a common hierarchy.
Use instanceof before casting: if (obj instanceof Dog) { Dog d = (Dog) obj; }. In Java 16+, use pattern matching: if (obj instanceof Dog d) { d.bark(); }
Generics enforce type constraints at compile time. List<String> only accepts Strings, so you never need to cast when retrieving elements, and the compiler catches type mismatches early.
It combines the instanceof check and cast: if (obj instanceof String s) { ... }. The variable s is automatically typed as String within the if block, eliminating the explicit cast.
Yes, it's a RuntimeException. But catching it is usually a sign of poor design. Better to use instanceof checks or generics to prevent it from occurring in the first place.
Explore 500+ free tutorials across 20+ languages and frameworks.