W3docs

Java instanceof-Operator

Laufzeittyp mit dem instanceof-Operator prüfen und Pattern Matching für instanceof in Java nutzen.

instanceof stellt eine Laufzeitfrage: „Ist diese Referenz tatsächlich ein T (oder ein Subtyp von T)?" Die Antwort ist ein boolean, und die moderne Pattern-Matching-Form bindet den Wert in einem einzigen Schritt zusätzlich an eine typisierte Variable — ein separater Cast ist nicht mehr nötig.

Es ist das Werkzeug, das man einsetzt, wenn man eine polymorphe Referenz hat und wissen möchte, welcher konkrete Typ sich dahinter verbirgt — typischerweise in equals, beim Durchlaufen heterogener Datenstrukturen oder beim Arbeiten mit versiegelten Hierarchien.

Die grundlegende Form

Die klassische Syntax lautet expression instanceof Type:

Object o = "hello";
if (o instanceof String) {
  String s = (String) o;
  System.out.println(s.length());
}

Die Prüfung gibt true zurück, wenn o auf einen String oder einen Subtyp zeigt, und false, wenn o null ist oder auf ein anderes Objekt verweist. null instanceof Anything ist immer false — eine kleine, aber nützliche Garantie.

Pattern Matching für instanceof

Seit Java 16 akzeptiert instanceof ein Typmuster, das eine Variable deklariert, die im selben Ausdruck an den eingeschränkten Typ gebunden wird:

if (o instanceof String s) {
  System.out.println(s.length());   // no cast needed
}

Gelingt die Prüfung, ist s im Scope und bereits als String typisiert. Schlägt sie fehl, ist s nicht im Scope. Der Cast entfällt, die Redundanz entfällt, und man kann nicht versehentlich etwas casten, das die Prüfung abgelehnt hat.

Gültigkeitsbereich der gebundenen Variable

Die gebundene Variable ist überall im Scope, wo der Compiler beweisen kann, dass die Prüfung erfolgreich war. Das schließt den if-Zweig ein, gilt aber auch durch && und in die Negation des if hinein:

if (o instanceof String s && s.length() > 3) { ... }   // s is in scope after && — also a String

if (!(o instanceof String s)) return;
System.out.println(s.length());   // s is in scope after the early return

Das zweite Muster eignet sich besonders gut für den Guard-Clause-Stil — den Typ einschränken, bei fehlendem Match aussteigen, den gebundenen Namen darunter frei verwenden.

Die Kehrseite ist ||: Die Bindung fließt nicht darüber hinaus, weil die rechte Seite genau dann ausgeführt wird, wenn die Prüfung fehlgeschlagen ist. o instanceof String s || s.length() > 0 kompiliert nicht — s ist rechts vom || nicht im Scope.

Einschränkungen beim Zieltyp

Der Compiler lehnt Prüfungen ab, die er als unmöglich erkennen kann. "hello" instanceof Integer kompiliert gar nicht erst, weil String und Integer nicht verwandt sind. Tippfehler und Refactoring-Überreste werden dadurch zur Build-Zeit statt zur Laufzeit aufgedeckt.

Er lehnt auch Upcasts ab, die nicht fehlschlagen können: Object o = ...; if (o instanceof Object) {} wird als überflüssig markiert.

In switch

Dieselbe Pattern-Matching-Maschinerie steht in switch zur Verfügung, wo sie bei versiegelten Hierarchien besonders glänzt:

String describe(Object o) {
  return switch (o) {
    case Integer i  -> "int " + i;
    case String  s  -> "str of length " + s.length();
    case int[]   a  -> "array of " + a.length;
    case null       -> "nothing";
    default         -> "something else";
  };
}

Mit einem versiegelten Typ als Selektor kann man default weglassen, und der Compiler verlangt einen Case für jeden erlaubten Subtyp — kombiniert mit sealed classes erhält man eine erschöpfende Case-Analyse.

Wann man es verwendet — und wann nicht

instanceof verwenden, wenn der Typ tatsächlich unbekannt ist und die Antwort das Verhalten beeinflusst: beim Implementieren von equals, beim Verarbeiten von Tagged-Union-Sealed-Hierarchien, beim Traversieren von AST-Knoten. Nicht als Ersatz für echte Polymorphie verwenden — eine Kette aus if (x instanceof A) ... else if (x instanceof B) ... über eine offene Hierarchie ist meist ein Zeichen dafür, dass eine virtuelle Methode auf dem Typ die Aufgabe besser erfüllen würde.

Ein ausgearbeitetes Beispiel

java— editable, runs on the server

Was kommt als Nächstes

instanceof ist eine von mehreren Methoden, auf die jedes Java-Objekt reagiert. Das nächste Kapitel tritt einen Schritt zurück und betrachtet das gesamte Paket — java.lang.Object, die Wurzelklasse, die jeder Typ stillschweigend erweitert, und die Methoden, die man davon erbt, ob man das wollte oder nicht. Weiter zu Java Object class.

Übungen

Übung
Was erspart Pattern Matching für `instanceof` (`if (o instanceof String s)`) im Vergleich zur klassischen Form?
Was erspart Pattern Matching für `instanceof` (`if (o instanceof String s)`) im Vergleich zur klassischen Form?
Was this page helpful?