HOWTO · Java
java.lang.ClassCastException in Java
Dieser Artikel hilft Ihnen bei der Behandlung der java.lang.ClassCastException in Java.
Auf dieser Seite
Eine java.lang.ClassCastException bedeutet, dass der Laufzeittyp eines Objekts nicht mit dem Typ kompatibel ist, der bei einer Typumwandlung angefordert wird. Vergleichen Sie zur Behebung den tatsächlichen Objekttyp mit dem Zieltyp der Umwandlung. Verwenden Sie anschließend instanceof, Generics mit passenden Typen oder einen anderen Entwurf, damit die Umwandlung gültig ist. Fangen Sie die Ausnahme nur ab, wenn das Programm sinnvoll darauf reagieren kann.
Was ist eine ClassCastException?
Java lässt eine Typumwandlung zu, wenn die Typen so miteinander verwandt sind, dass sie zur Laufzeit gültig sein könnte. Die Umwandlung ändert das Objekt nicht. Zur Laufzeit prüft Java, ob das Objekt eine Instanz der Zielklasse ist oder das Ziel-Interface implementiert. Ist das nicht der Fall, löst Java eine java.lang.ClassCastException aus.
Wenn beispielsweise Dog und Cat beide von Animal erben, kann eine Referenz vom Typ Animal auf eines der beiden Objekte verweisen. Eine Animal-Referenz darf nur dann in Dog umgewandelt werden, wenn das referenzierte Objekt tatsächlich ein Dog ist. Ein Cat-Objekt lässt sich nicht in seinen gleichrangigen Typ Dog umwandeln. Umgekehrt ist es sicher, ein Dog einer Animal-Referenz zuzuweisen: Diese Aufwärtsumwandlung ist gültig, weil jedes Dog ein Animal ist.
Warum löst Java eine ClassCastException aus?
Meist liegt die Ursache in der Annahme, dass eine allgemein typisierte Referenz ein bestimmtes Unterklassenobjekt enthält. Der Compiler kann prüfen, ob eine Abwärtsumwandlung grundsätzlich möglich ist, weiß aber nicht immer, auf welches Objekt die Referenz zur Laufzeit zeigt. Die Laufzeitprüfung erkennt, wenn der tatsächliche Typ nicht zum Zieltyp passt.
Das kommt häufig vor, wenn Code Werte als Object erhält, eine ältere Sammlung ohne Generics verwendet oder Annahmen über die konkrete Klasse eines von einer API zurückgegebenen Objekts trifft. Polymorphie an sich ist nicht das Problem: Eine überschriebene Methode über eine Referenz auf die Oberklasse aufzurufen, ist sicher. Der Fehler entsteht, wenn der Code die Referenz auf einen Untertyp einschränken will, zu dem das Objekt nicht gehört.
Rohe Sammlungen und nicht geprüfte Konvertierungen können außerdem die Typprüfungen von Generics umgehen. Beim späteren Abruf eines Werts kann eine implizite Typumwandlung eingefügt werden, die bei seiner Verwendung fehlschlägt. Suchen Sie danach, wo der Wert in die Sammlung gelangt ist und an welcher Stelle sein Typ angenommen wurde. Nur die auslösende Zeile zu ändern, kann die eigentliche Ursache des Typkonflikts verdecken.
So verhindern Sie eine ClassCastException
Deklarieren Sie Referenzen und Sammlungen möglichst mit dem spezifischsten sinnvollen Typ. Generics ermöglichen es dem Compiler, das Einfügen und Abrufen von Sammlungselementen zu prüfen, und verringern so den Bedarf an Typumwandlungen. Sie machen eine ausdrückliche Umwandlung eines beliebigen Objekts jedoch nicht sicher. Rohe Typen und nicht geprüfte Operationen können diesen Schutz weiterhin aushebeln.
Eine Abwärtsumwandlung kann kompilieren, wenn Quell- und Zielklasse miteinander verwandt sind, und dennoch fehlschlagen, wenn das Objekt tatsächlich einer gleichrangigen Unterklasse angehört. Das folgende Beispiel fängt den Fehler ab, damit das Programm normal beendet werden kann. Der Code und die darin enthaltenen Bezeichnungen und Ausgaben bleiben unverändert; englische Texte in den Beispielblöcken werden daher nicht übersetzt:
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
public class FailingCastExample {
static class Animal {}
static class Dog extends Animal {}
static class Cat extends Animal {}
public static void main(String[] args) {
Animal animal = new Cat();
try {
Dog dog = (Dog) animal;
System.out.println(dog);
} catch (ClassCastException exception) {
System.out.println(exception.getClass().getName());
}
}
}
java.lang.ClassCastException
Der catch-Block fängt eine java.lang.ClassCastException ab: Das Objekt ist ein Cat, kein Dog. Die von der JVM erzeugte Meldung und der Stacktrace können je nach Laufzeit variieren. Verwenden Sie daher den Ausnahmetyp und die Zeile mit der Typumwandlung, um den Konflikt zu diagnostizieren. Lassen Sie den Wert als Animal typisiert, wenn kein Verhalten benötigt wird, das speziell für einen Untertyp gilt.
Wenn ein Wert absichtlich allgemein typisiert ist, prüfen Sie seinen Laufzeittyp, bevor Sie ihn in einen spezifischeren Typ umwandeln. Das eigenständige Beispiel zeigt eine sichere Typumwandlung:
public class CastExample {
static class Animal {
String name() { return "Milo"; }
}
static class Dog extends Animal {
String bark() { return "woof"; }
}
public static void main(String[] args) {
Animal animal = new Dog();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
System.out.println(dog.bark());
}
}
}
Die Typumwandlung ist durch instanceof abgesichert und wird daher nur ausgeführt, wenn das Objekt ein Dog ist. Wenn kein Verhalten benötigt wird, das speziell für einen Untertyp gilt, lassen Sie den Wert als Animal typisiert und verwenden Sie stattdessen dessen gemeinsame API. Bei Java-Versionen mit Pattern Matching für instanceof lassen sich Prüfung und Bindung zusammenfassen. Dieses Beispiel verwendet aus Gründen der breiten Kompatibilität die herkömmliche Syntax.
So behandeln und diagnostizieren Sie eine ClassCastException
Lesen Sie die Fehlermeldung und den Stacktrace, um den Quelltyp, den angeforderten Zieltyp und die Zeile der Typumwandlung zu ermitteln. Verfolgen Sie dann den Wert bis zu seiner Quelle zurück: Prüfen Sie das zurückgegebene Objekt, den Inhalt der Sammlung, die Deserialisierungszuordnung oder den API-Vertrag. Fügen Sie an der Stelle, an der die Annahme getroffen wird, eine Typprüfung ein oder korrigieren Sie das deklarierte Datenmodell.
Ein try-catch-Block ist sinnvoll, wenn eine fehlgeschlagene Typumwandlung bei der Eingabe erwartet werden kann und das Programm darauf reagieren kann, etwa indem es beim Verarbeiten weiterer Datensätze einen einzelnen fehlerhaften Datensatz zurückweist. Eine ClassCastException rund um gewöhnliche Anwendungslogik abzufangen und ohne Korrektur der Annahme fortzufahren, kann zu unvollständigen Daten führen oder einen Fehler verdecken. Halten Sie den try-Block eng begrenzt und geben Sie genügend Kontext aus, um den problematischen Wert diagnostizieren zu können. Hier wird keine Fehlermeldung gezeigt, da ihr Wortlaut je nach Java-Implementierung und Laufzeitversion variieren kann.
Häufig gestellte Fragen
Was ist eine java.lang.ClassCastException?
Bei einem Klassenziel löst Java die Ausnahme aus, wenn das Objekt keine Instanz dieser Klasse ist. Bei einem Interface-Ziel geschieht das, wenn das Objekt dieses Interface nicht implementiert. Eine Umwandlung in die Klasse des Objekts selbst oder in eine kompatible Oberklasse beziehungsweise ein kompatibles Interface ist erfolgreich.
Wie kann ich eine ClassCastException in Java vermeiden?
Verwenden Sie möglichst genaue deklarierte Typen und Generics. Prüfen Sie mit instanceof, ob eine Abwärtsumwandlung zulässig ist, wenn der Laufzeittyp nicht bereits feststeht. Diese Maßnahmen verringern unsichere Umwandlungen, können aber nicht jede beliebige Typumwandlung gültig machen.
Was passiert, wenn ich die Ausnahme nicht behandle?
Wird sie nicht abgefangen, wird sie im Aufrufstack des aktuellen Threads nach oben weitergegeben und kann dessen Arbeit beenden. Welche Folgen das für die gesamte Anwendung hat, hängt vom Thread und der umgebenden Fehlerbehandlung ab.
Kann ich eine ClassCastException mit try-catch abfangen?
Ja. Fangen Sie sie ab, wenn eine sinnvolle Wiederherstellung möglich ist. Andernfalls korrigieren Sie die inkompatible Typumwandlung oder die fehlerhafte Annahme über den Ursprungstyp.
Ist die Verwendung von instanceof eine gute Praxis?
Verwenden Sie es, wenn das Verhalten tatsächlich vom Laufzeituntertyp eines Objekts abhängt. Wenn sich wiederholte Typprüfungen im Code häufen, sollten Sie erwägen, das untertypspezifische Verhalten in polymorphe Methoden zu verlagern oder das Datenmodell neu zu entwerfen.