← Debugging Guides

阅读中文版本

Java — ClassCastException at runtime

Resolve ClassCastException by tracing the actual runtime type and correcting generics or casts.

beginnerdebuggingjavatypes

Symptoms

  • java.lang.ClassCastException: class A cannot be cast to class B
  • The cast compiles but fails at runtime
  • Raw types or unchecked casts hide the mismatch
  • Deserialization produces an unexpected type

Possible causes

  • An unchecked cast assumes a type the value does not have
  • Raw collections or maps hold mixed types
  • A generic type parameter is erased so the cast is not verified
  • Deserialization into a base type yields a subtype different from the expected one

Diagnosis steps

Read the runtime types in the message

App 2>&1 | grep ClassCastException

Interpretation

The message names the actual class and the target class, which reveals where the assumption broke.

Find the unchecked cast

javac -Xlint:unchecked src/*.java

Interpretation

Warning on unchecked casts points to the lines where the compiler cannot guarantee the type.

Log the actual class before casting

System.out.println(value.getClass())

Interpretation

Printing the runtime class confirms what the value really is, rather than what the code assumed.

Root cause

A cast assumed a runtime type the value did not have. Type erasure means many casts are unchecked, so the mismatch surfaces only when the code actually runs with that value.

Fix

Correct the generic types so casts are checked, avoid raw collections, verify with instanceof before casting, and align deserialization targets with the actual payload.

Verify the fix

Rerun the failing path and confirm the cast no longer throws, and confirm the value is of the intended type by logging or asserting it.

Symptom walkthrough

A cast compiles but throws ClassCastException when the code runs with certain data. Type erasure makes generic casts unchecked, so the compiler cannot always prevent a mismatch; raw collections and maps make it more likely by allowing mixed element types. The message names both the actual and target classes, which pinpoints the false assumption.

Fix in practice

Use checked generics instead of raw types, guard casts with instanceof where the runtime type varies, and make deserialization targets match the real payload. Prefer polymorphic dispatch over casting so the correct behavior is selected without an explicit cast.

Verification

Rerun the failing path and confirm the cast succeeds, then log or assert the runtime type to be sure the value is what the code now expects. Both the absence of the exception and the correct type matter.

Diagnostic commands

Check the behavior with commands like these:

App 2>&1 | grep ClassCastException
javac -Xlint:unchecked src/*.java
System.out.println(value.getClass())