Java-Typumwandlung erklärt (von Anfänger bis Fortgeschrittene): Numerische Umwandlung, Upcasting/Downcasting, instanceof und häufige Fallstricke

目次

1. Was ist Casting in Java? (Kurze Antwort)

In Java bedeutet Casting, einen Wert oder ein Objekt als einen anderen Typ zu behandeln.
Du verwendest Casting, wenn du Zahlen umwandeln möchtest (z. B. double zu int) oder wenn du ein Objekt als einen spezifischeren Klassentyp behandeln möchtest (z. B. Animal zu Dog).

Casting ist mächtig, aber es kann auch riskant sein:

  • Numerisches Casting kann den tatsächlichen Wert ändern (durch Abschneiden von Dezimalstellen oder Überlaufen).
  • Referenz-Casting kann Laufzeitfehler verursachen, wenn der echte Objekttyp nicht übereinstimmt.

Dieser Artikel erklärt Java-Casting auf eine Weise, die dir hilft, sicheren Code zu schreiben und gängige Fallen zu vermeiden.

1.1 Was du in diesem Leitfaden lernen wirst

Java-Casting wird viel einfacher, sobald du es in zwei Kategorien unterteilst:

  • Numerisches Casting (primitive Typen) Casting zwischen Typen wie int , long , double usw. Die Schlüsselfrage ist, ob die Umwandlung sicher ist oder Informationen verliert.
  • Referenz-Casting (Klassen und Interfaces) Casting von Objekten in einer Vererbungshierarchie, wie Upcasting und Downcasting. Die Schlüsselfrage ist, ob der echte Laufzeittyp des Objekts zum Cast passt.

Wenn du diese beiden Themen zu früh mischst, wirkt Casting verwirrend.
Deshalb lernen wir sie Schritt für Schritt.

1.2 Häufige Situationen, in denen Casting verwendet wird

Beispiel 1: Umwandeln einer Dezimalzahl in eine Ganzzahl

double price = 19.99;
int yen = (int) price; // 19 (decimal part is removed)

Dies ist eine Verkleinerungsumwandlung, daher erfordert Java explizites Casting.

Beispiel 2: Behandeln einer Referenz vom Parent-Typ als Child-Typ

Animal a = new Dog();   // upcasting
Dog d = (Dog) a;        // downcasting

Das funktioniert nur, wenn das tatsächliche Objekt wirklich ein Dog ist.
Andernfalls stürzt das Programm zur Laufzeit ab.

1.3 Die zwei HauptRisiken von Casting

Casting wird aus zwei Hauptgründen gefährlich:

1) Numerisches Casting kann den Wert ändern

  • Dezimalstellen werden abgeschnitten (nicht gerundet)
  • Werte können überlaufen, wenn der Zieltyp zu klein ist

2) Referenz-Casting kann dein Programm zum Absturz bringen

  • Falsche Downcasts verursachen ClassCastException

Wenn du dich an diese zwei Risiken erinnerst, vermeidest du die meisten Casting-Fehler.

1.4 Begriffe, die Leute mit Casting verwechseln

Bevor wir fortfahren, hier sind ein paar Begriffe, die ähnlich aussehen, aber etwas anderes bedeuten:

  • Implizite Umwandlung Java wandelt Typen automatisch in sicheren Situationen um (meist Vergrößerungsumwandlungen).
  • Explizites Casting Du schreibst (type) manuell, wenn Informationen verloren gehen könnten.
  • Boxing / Unboxing Automatische Umwandlung zwischen Primitiven ( int ) und Wrapper-Klassen ( Integer ). Das ist nicht dasselbe wie Casting, verursacht aber oft Fehler.

2. Java-Casting hat zwei Typen: Numerisch vs. Referenz

Um Java-Casting korrekt zu verstehen, musst du es aufteilen in:

  • Numerisches Casting (primitive Typen)
  • Referenz-Casting (Objekte)

Diese beiden folgen unterschiedlichen Regeln und verursachen unterschiedliche Arten von Problemen.

2.1 Numerisches Casting (Primitive Typen)

Numerisches Casting wandelt einen primitiven numerischen Typ in einen anderen um, wie z. B.:

  • Ganzzahlen: byte , short , int , long
  • Gleitkommazahlen: float , double
  • Zeichen: char (intern numerisch)

Beispiel: Numerisches Casting

double d = 10.5;
int i = (int) d; // 10

Dies ist eine Verkleinerungsumwandlung, daher ist explizites Casting erforderlich.

Vergrößerungs- vs. Verkleinerungsumwandlungen (Wichtig)

Numerische Umwandlungen werden gruppiert in:

  • Vergrößerungsumwandlung (kleinerer → größerer Bereich) Beispiel: int → long , int → double Meist sicher, daher erlaubt Java implizite Umwandlung.
  • Verkleinerungsumwandlung (größerer → kleinerer Bereich) Beispiel: double → int , long → short Riskant, daher erfordert Java explizites Casting.

2.2 Referenz-Casting (Klassen und Interfaces)

Referenz-Casting ändert, wie ein Objekt in einer Vererbungshierarchie behandelt wird.

Es geht nicht darum, das Objekt selbst zu ändern, sondern den Typ der Referenz zu ändern.

Beispielhierarchie:

  • Animal (Eltern)
  • Dog (Kind)
    Animal a = new Dog(); // upcasting
    Dog d = (Dog) a;      // downcasting
    

Referenz-Casting ist eng mit Polymorphismus in der objektorientierten Programmierung verbunden.

2.3 „Gefahr“ bedeutet unterschiedliche Dinge bei numerischem vs. Referenz-Casting

Das ist das wichtigste mentale Modell:

Risiko beim numerischen Casting

  • Der Code läuft, aber der Wert kann unerwartet ändern.

Risiko beim Referenz-Casting

  • Der Code kompiliert, aber das Programm kann zur Laufzeit abstürzen.

2.4 Wichtige Erkenntnis (Merken Sie sich das)

Wenn Sie sich je festgefahren fühlen, kommen Sie hierher zurück:

  • Numerisches Casting → „Sie können konvertieren, aber der Wert könnte sich ändern.“
  • Referenz-Casting → „Sie können casten, aber ein falsches Casting kann abstürzen.“

3. Numerisches Casting in Java: Implizites vs. Explizites Casting

Das numerische Casting in Java wird einfach, sobald Sie eine einfache Regel verstehen:

  • Erweiternde Konversionen sind in der Regel automatisch (implizit).
  • Verengende Konversionen erfordern manuelles Casting (explizit), da Daten verloren gehen können.

Dieser Abschnitt erklärt den Unterschied mit praktischen Beispielen und häufigen Fehlern.

3.1 Implizites Casting (Erweiternde Konversion) Beispiele

Java erlaubt implizite Konversion, wenn der Zieltyp den ursprünglichen Wertebereich sicher darstellen kann.

Beispiel: intdouble

int i = 10;
double d = i;

System.out.println(d); // 10.0

Das ist sicher, weil double einen viel größeren Bereich als int darstellen kann.

Beispiel: byteint

byte b = 100;
int i = b;

System.out.println(i); // 100

Da int einen breiteren Bereich als byte hat, konvertiert Java automatisch.

3.2 Explizites Casting (Verengende Konversion) und Abbruchsverhalten

Beim Konvertieren zu einem kleineren oder eingeschränkteren Typ erfordert Java explizites Casting.

Beispiel: doubleint

double d = 10.9;
int i = (int) d;

System.out.println(i); // 10

Wichtiges Detail:

  • Casting zu int rundet nicht .
  • Es kürzt den Dezimalteil ab.

Also:

  • 10.9 wird 10
  • 10.1 wird 10
  • -10.9 wird -10 (bewegt sich zur Null hin)

Beispiel: longint

long l = 100L;
int i = (int) l;

System.out.println(i); // 100

Das sieht sicher aus, aber es wird gefährlich, wenn der long-Wert den int-Bereich überschreitet.

3.3 Überlauf und Unterlauf: Die versteckte Gefahr

Verengende Konversionen sind riskant nicht nur, weil Dezimalstellen entfernt werden, sondern auch weil Werte überlaufen können.

Beispiel: Casting eines großen long in int

long l = 3_000_000_000L; // 3 billion (too large for int)
int i = (int) l;

System.out.println(i); // unexpected result

Das ist einer der schlimmsten Arten von Fehlern, weil:

  • Der Code kompiliert
  • Das Programm läuft
  • Aber der Wert wird stillschweigend falsch

3.4 Häufiger Compiler-Fehler: „Possible Lossy Conversion“

Wenn Sie eine verengende Konversion ohne explizites Casting versuchen, stoppt Java Sie mit einem Compiler-Fehler.

Beispiel: double zu int ohne Casting

double d = 1.5;
int i = d; // compile-time error

Die Meldung enthält normalerweise etwas wie:

  • possible lossy conversion

Bedeutung:

  • „Diese Konversion kann Informationen verlieren.“
  • „Sie müssen das Casting manuell schreiben, wenn Sie es wirklich wollen.“

Beispiel: long zu int ohne Casting

long l = 100L;
int i = l; // compile-time error

Auch wenn 100 sicher ist, blockt Java es, weil long viel größere Werte halten könnte.

3.5 Unerwartetes Casting-Verhalten in Ausdrücken

Ein häufiger Anfängerfehler ist anzunehmen, dass Java in der Division automatisch Dezimalzahlen produziert.

Beispiel: Ganzzahldivision kürzt Ergebnisse

int a = 5;
int b = 2;

System.out.println(a / b); // 2

Weil beide Operanden int sind, ist das Ergebnis auch int.

Korrektur: Casten Sie einen Operanden zu double

int a = 5;
int b = 2;

System.out.println((double) a / b); // 2.5

Das erzwingt Gleitkomma-Division.

3.6 Praktische Faustregel (Für reale Projekte)

Um numerische Casting‑Fehler zu vermeiden, befolgen Sie diese Regeln:

  • Widening‑Konvertierungen sind sicher genug für implizite Konvertierung.
  • Narrowing‑Konvertierungen müssen explizit sein, und Sie müssen akzeptieren, dass sich Werte ändern können.
  • Seien Sie immer vorsichtig beim Konvertieren: wp:list /wp:list

    • Gleitkomma → Ganzzahl (Abrundung)
    • großer Typ → kleinerer Typ (Überlauf)

4. Referenz‑Casting: Upcasting vs Downcasting

Referenz‑Casting befasst sich mit Objekten, nicht mit numerischen Werten.
Statt eine Zahl zu konvertieren, ändern Sie, wie Java eine Objekt‑Referenz innerhalb einer Vererbungshierarchie behandelt.

Die wichtigste Regel lautet:

Beim Referenz‑Casting zählt der tatsächliche Laufzeittyp des Objekts, nicht der Variablentyp.

4.1 Upcasting (Kind → Elternteil) ist sicher und meist implizit

Upcasting bedeutet, ein Objekt einer Kindklasse als Typ seiner Elternklasse zu behandeln.
Das ist in Java extrem verbreitet und im Allgemeinen sicher.

Beispiel: Upcasting eines Dog zu einem Animal

class Animal {
    void eat() {
        System.out.println("eat");
    }
}

class Dog extends Animal {
    void bark() {
        System.out.println("bark");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();

        Animal a = dog; // upcasting (implicit)
        a.eat();        // OK
    }
}

Das funktioniert, weil jeder Dog ein Animal ist.

4.2 Was Sie beim Upcasting verlieren

Upcasting ist sicher, aber es ändert, welche Methoden über den Referenztyp sichtbar sind.

Animal a = new Dog();
a.bark(); // compile-time error

Obwohl das reale Objekt ein Dog ist, ist der Variablentyp Animal, sodass Java nur Methoden zulässt, die in Animal definiert sind.

4.3 Downcasting (Elternteil → Kind) ist riskant und erfordert explizites Casting

Downcasting bedeutet, eine Referenz des Elterntyps zurück in einen Kindtyp zu konvertieren.

Animal a = new Dog();
Dog d = (Dog) a; // downcasting (explicit)
d.bark();        // OK

Das funktioniert nur, wenn das reale Objekt tatsächlich ein Dog ist.

4.4 Warum Downcasting gefährlich ist: ClassCastException

Ist das reale Objekt nicht vom Zieltyp, stürzt das Programm zur Laufzeit ab.

Animal a = new Animal();
Dog d = (Dog) a; // ClassCastException at runtime

Das kompiliert, weil Java eine mögliche Vererbungsbeziehung erkennt, aber zur Laufzeit kann das Objekt nicht zu einem Dog werden.

4.5 Variablentyp vs Laufzeittyp (Das Schlüsselkonzept)

Animal a = new Dog();

In diesem Fall:

  • Variablentyp (Compile‑Time): Animal
  • Laufzeittyp (tatsächliches Objekt): Dog

Java erlaubt das wegen Polymorphie, aber Downcasting muss zum Laufzeittyp passen.

5. Verwenden Sie instanceof vor dem Downcasting (Das sichere Muster)

Um ClassCastException zu verhindern, sollten Sie zuerst den Laufzeittyp prüfen.

5.1 Was instanceof macht

instanceof prüft, ob ein Objekt eine Instanz eines bestimmten Typs ist.

if (obj instanceof Dog) {
    // obj can be treated as a Dog safely
}

Das prüft den tatsächlichen Laufzeittyp, nicht den deklarierten Variablentyp.

5.2 Das standardmäßige sichere Downcasting‑Muster

Animal a = new Dog();

if (a instanceof Dog) {
    Dog d = (Dog) a;
    d.bark();
}

Das verhindert Abstürze, indem sichergestellt wird, dass das Casting nur bei gültigem Typ erfolgt.

5.3 Was ohne instanceof passiert (häufiger Absturz)

Animal a = new Animal();
Dog d = (Dog) a; // runtime crash

Deshalb gilt instanceof als das Standard‑Sicherheitswerkzeug.

5.4 Pattern Matching für instanceof (Klarere moderne Syntax)

Neuere Java‑Versionen unterstützen eine lesbarere Form:

Traditioneller Stil

if (a instanceof Dog) {
    Dog d = (Dog) a;
    d.bark();
}

Pattern‑Matching‑Stil

if (a instanceof Dog d) {
    d.bark();
}

Vorteile:

  • Keine manuelle Cast‑Anweisung nötig
  • Die Variable d existiert nur innerhalb des if‑Blocks
  • Klarerer und sicherer Code

5.5 Wenn instanceof zu einem Designgeruch wird

Wenn Sie überall Code wie diesen schreiben:

if (a instanceof Dog) {
    ...
} else if (a instanceof Cat) {
    ...
} else if (a instanceof Bird) {
    ...
}

Das kann bedeuten, dass Ihrem Design Polymorphie oder eine bessere Schnittstellenstruktur fehlt.

Im nächsten Abschnitt werden wir besprechen, wie man Casting reduziert, indem man das Design verbessert.

6. Wie man Casting im realen Java-Design reduziert

Casting ist manchmal notwendig, aber in professionellen Codebasen weist häufiges Casting oft auf ein Designproblem hin.

Wenn Sie viel davon sehen:

  • instanceof‑Prüfungen
  • wiederholte Downcasts
  • lange if/else‑Ketten nach Typ

…bedeutet das in der Regel, dass der Code gegen objektorientiertes Design kämpft, anstatt es zu nutzen.

6.1 Das klassische „Casting‑Explosion“-Muster

Hier ein häufiges Anti‑Pattern:

void process(Animal a) {
    if (a instanceof Dog) {
        Dog d = (Dog) a;
        d.bark();
    } else if (a instanceof Cat) {
        Cat c = (Cat) a;
        c.meow();
    }
}

Das funktioniert, erzeugt aber langfristige Probleme:

  • Das Hinzufügen eines neuen Subtyps zwingt Sie, process() zu ändern
  • Die Methode muss jeden Subtyp kennen
  • Der Code wird schwerer zu warten und zu erweitern

6.2 Verwenden Sie Polymorphie statt Casting

Die saubere Lösung besteht darin, das Verhalten in die Klassenhierarchie zu verlagern.

class Animal {
    void sound() {
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("bark");
    }
}

class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("meow");
    }
}

Jetzt wird Ihre Logik einfach und ohne Casts:

void process(Animal a) {
    a.sound(); // no casting needed
}

Das ist die Kernidee der Polymorphie:

  • Der Methodenaufruf bleibt gleich
  • Der Laufzeittyp bestimmt das Verhalten

6.3 Definieren Sie erforderliches Verhalten in einem übergeordneten Typ oder Interface

Viele Casts entstehen aus einem Grund:

“Ich brauche eine kind‑spezifische Methode, aber der übergeordnete Typ definiert sie nicht.”

Wenn das Verhalten wirklich erforderlich ist, definieren Sie es auf oberster Ebene.

Beispiel: Interface‑basiertes Design

interface Speaker {
    void speak();
}

class Dog implements Speaker {
    public void speak() {
        System.out.println("bark");
    }
}

class Cat implements Speaker {
    public void speak() {
        System.out.println("meow");
    }
}

Jetzt können Sie schreiben:

void process(Speaker s) {
    s.speak(); // no downcast needed
}

6.4 Wann Downcasting tatsächlich sinnvoll ist

Downcasting ist nicht immer schlecht. Es kann akzeptabel sein, wenn:

  • ein Framework generische Typen wie Object zurückgibt
  • Sie Legacy‑APIs integrieren
  • Sie Ereignisse oder Callbacks mit gemeinsamen Basistypen behandeln

Selbst dann sollten Sie es sicher handhaben:

  • mit instanceof prüfen
  • den Cast in einem kleinen, kontrollierten Bereich halten
  • das Verteilen von Casts im gesamten Code vermeiden

7. Boxing/Unboxing vs Casting (häufige Verwirrung)

Java hat zwei Welten von numerischen Typen:

  • Primitive : int , double , usw.
  • Wrapper‑Klassen : Integer , Double , usw.

Die automatische Umwandlung zwischen ihnen heißt:

  • Boxing : Primitive → Wrapper
  • Unboxing : Wrapper → Primitive

Das ist nicht dasselbe wie Casting, kann aber Laufzeitfehler verursachen.

7.1 Autoboxing‑Beispiel (intInteger)

int x = 10;
Integer y = x; // autoboxing
System.out.println(y); // 10

7.2 Auto‑Unboxing‑Beispiel (Integerint)

Integer x = 10;
int y = x; // auto-unboxing
System.out.println(y); // 10

7.3 Der gefährliche Fall: null + Unboxing = Absturz

Integer x = null;
int y = x; // NullPointerException

Das sieht aus wie eine normale Zuweisung, aber Unboxing erfordert ein echtes Objekt.

7.4 Falle beim Vergleich von Wrappern: Verwenden Sie nicht == für Werte

Integer a = 1000;
Integer b = 1000;

System.out.println(a == b); // may be false

Verwenden Sie equals() für den Wertvergleich:

System.out.println(a.equals(b)); // true

8. Generics und Casting: Verständnis von unchecked-Warnungen

In realen Projekten sehen Sie häufig Warnungen wie:

  • unchecked cast
  • unchecked conversion

Diese Warnungen bedeuten:

„Der Compiler kann nicht beweisen, dass dieser Cast typsicher ist.“

8.1 Häufige Ursache: Rohtypen

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList(); // raw type
        list.add("Hello");

        List<Integer> numbers = (List<Integer>) list; // unchecked warning
        Integer x = numbers.get(0); // may crash
        System.out.println(x);
    }
}

Das ist unsicher, weil die Liste tatsächlich ein String enthält.

8.2 Lösung: Verwenden Sie korrekte generische Typen

List<String> list = new ArrayList<>();
list.add("Hello");

String s = list.get(0);
System.out.println(s);

Kein Cast erforderlich, und der Compiler schützt Sie.

8.3 Wenn Sie Warnungen unterdrücken müssen, halten Sie es minimal

Manchmal lässt sich ein Cast nicht vermeiden (Legacy-APIs, externe Bibliotheken).
In solchen Fällen:

  • Cast an einer kleinen Stelle
  • Dokumentieren, warum er sicher ist
  • Warnungen nur im kleinsten Geltungsbereich unterdrücken

Beispiel:

@SuppressWarnings("unchecked")
List<String> list = (List<String>) obj;

9. Häufige Casting-Fehler (kurze Copy-Paste-Beispiele)

Casting ist leicht „theoretisch zu verstehen“, führt aber in realem Code leicht zu Fehlern.
Dieser Abschnitt zeigt die häufigsten Fehler mit kurzen Beispielen, die Sie schnell reproduzieren können.

Der beste Weg, Casting zu lernen, ist:

  • Den Fehler sehen
  • Verstehen, warum er fehlschlägt
  • Die sichere Lösung lernen

9.1 Numerisches Casting: Erwartung von Rundung statt Abschneiden

Fehler: Annahme, dass (int) den Wert rundet

double x = 9.9;
int y = (int) x;

System.out.println(y); // 9

Java rundet hier nicht. Es schneidet den Dezimalteil ab.

9.2 Numerisches Casting: Überraschung bei Ganzzahldivision

Fehler: Erwartung von 2.5, aber Ergebnis ist 2

int a = 5;
int b = 2;

System.out.println(a / b); // 2

Da beide Operanden int sind, ist das Ergebnis ebenfalls int.

Lösung: Einen Operanden zu double casten

int a = 5;
int b = 2;

System.out.println((double) a / b); // 2.5

9.3 Numerisches Casting: Überlauf beim Casten großer Zahlen

Fehler: Einen großen long in int casten

long l = 3_000_000_000L;
int i = (int) l;

System.out.println(i); // unexpected value

Das kompiliert und läuft, aber der Wert wird aufgrund des Überlaufs inkorrekt.

9.4 Referenz-Casting: Downcasting-Absturz (ClassCastException)

Fehler: Ein Objekt in den falschen Subtyp casten

class Animal {}
class Dog extends Animal {}

public class Main {
    public static void main(String[] args) {
        Animal a = new Animal();
        Dog d = (Dog) a; // ClassCastException
    }
}

Lösung: instanceof verwenden

Animal a = new Animal();

if (a instanceof Dog) {
    Dog d = (Dog) a;
    // safe usage
} else {
    System.out.println("Not a Dog, so no cast.");
}

9.5 Referenz-Casting: Verlust von Kind-Methoden nach Upcasting

Fehler: „Es ist ein Hund, warum kann ich nicht bark() aufrufen?“

class Animal {}
class Dog extends Animal {
    void bark() {
        System.out.println("bark");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        // a.bark(); // compile-time error
    }
}

Der Variablentyp ist Animal, daher erlaubt Java nur Methoden, die in Animal deklariert sind.

9.6 Generics: Ignorieren von unchecked cast und Laufzeitfehler

Fehler: Rohtyp + unsicherer Cast

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList(); // raw type
        list.add("Hello");

        List<Integer> numbers = (List<Integer>) list; // unchecked warning
        Integer x = numbers.get(0); // may crash
        System.out.println(x);
    }
}

Lösung: Generics korrekt verwenden

List<String> list = new ArrayList<>();
list.add("Hello");

String s = list.get(0);
System.out.println(s);

9.7 Wrapper-Vergleichsfalle: Verwendung von == anstelle von equals()

Fehler: Vergleich von Wrapper-Werten mit ==

Integer a = 1000;
Integer b = 1000;

System.out.println(a == b); // may be false

Lösung: Verwende equals()

System.out.println(a.equals(b)); // true

9.8 Null-Unboxing-Absturz (NullPointerException)

Fehler: Unboxing von null

Integer x = null;
int y = x; // NullPointerException

Lösung: Auf null prüfen (oder nach Möglichkeit Primitive verwenden)

Integer x = null;

if (x != null) {
    int y = x;
    System.out.println(y);
} else {
    System.out.println("x is null");
}

10. FAQ (Java-Casting-Fragen)

10.1 Was ist Casting (Typumwandlung) in Java?

Casting bedeutet, einen Wert oder ein Objekt als einen anderen Typ zu behandeln.

Java-Casting hat zwei Hauptkategorien:

  • numerisches Casting (Primitive)
  • Referenz-Casting (Objekte)

10.2 Was ist der Unterschied zwischen impliziter Konvertierung und explizitem Casting?

  • Implizite Konvertierung erfolgt automatisch in sicheren Situationen (meist Erweiterungskonvertierungen).
  • Explizites Casting erfordert (type) und ist nötig, wenn Daten verloren gehen können (Verengungskonvertierungen).

10.3 Rundet (int) 3.9 die Zahl?

Nein. Es wird abgeschnitten.

System.out.println((int) 3.9); // 3

10.4 Warum ist das Casting von double zu int riskant?

Weil es Dezimalstellen entfernt (Datenverlust). Außerdem können große Werte überlaufen, wenn sie in kleinere numerische Typen gecastet werden.

10.5 Was ist der Unterschied zwischen Upcasting und Downcasting?

  • Upcasting (Kind → Elternteil) ist sicher und meist implizit.
  • Downcasting (Elternteil → Kind) ist riskant und erfordert explizites Casting.

Falsches Downcasting kann ClassCastException verursachen.

10.6 Was verursacht ClassCastException und wie behebe ich das?

Es tritt auf, wenn der tatsächliche Laufzeittyp des Objekts nicht mit dem Zieltyp des Casts übereinstimmt.

Behebe es, indem du vor dem Casten mit instanceof prüfst.

10.7 Sollte ich immer instanceof vor dem Downcasting verwenden?

Wenn die Möglichkeit besteht, dass der Laufzeittyp nicht übereinstimmt, ja. Das ist der standardmäßige sichere Ansatz.

Modernes Java unterstützt außerdem Pattern Matching:

if (a instanceof Dog d) {
    d.bark();
}

10.8 Ist es in Ordnung, unchecked cast-Warnungen zu ignorieren?

In der Regel nein.

Die meisten unchecked-Warnungen entstehen durch rohe Typen oder unsichere Casts. Behebe die Ursache, indem du Generics korrekt nutzt.

Wenn du es wirklich nicht vermeiden kannst (Legacy-APIs), isoliere den Cast und unterdrücke die Warnungen im kleinsten möglichen Umfang.

10.9 Wie kann ich Code entwerfen, um zu viele Casts zu vermeiden?

Verwende objektorientierte Design-Features wie:

  • Polymorphie (Verhalten in Unterklassen überschreiben)
  • Schnittstellen (erforderliches Verhalten in einem gemeinsamen Typ definieren)

Wenn du ständig instanceof-Ketten schreibst, kann das ein Hinweis darauf sein, dass das Design verbessert werden muss.