instanceof în Java

Pattern matching Java 1.0 (cu pattern: Java 16)

instanceof verifică dacă un obiect este de un anumit tip; în forma nouă declară și o variabilă deja convertită la acel tip.

Sintaxă
obiect instanceof Tip            // true / false
obiect instanceof Tip variabila  // verifică și declară variabila (Java 16)

Ce face instanceof

x instanceof Tip dă true dacă obiectul din x este de tipul Tip sau al unei subclase / implementări a lui. Pentru null rezultatul este mereu false, deci instanceof nu aruncă niciodată NullPointerException.

Înainte de Java 16, după verificare urma o conversie explicită: if (o instanceof String) { String s = (String) o; ... }. Forma cu pattern face ambele dintr-o dată: if (o instanceof String s). Variabila s există doar acolo unde compilatorul știe sigur că testul a reușit.

Când ai multe ramuri instanceof la rând, un switch cu pattern-uri este de obicei mai clar. Iar dacă te trezești testând tipul ca să alegi comportamentul, poate e mai bine o metodă rescrisă în fiecare subclasă (polimorfism).

Ce returnează

boolean: true dacă obiectul nu este null și este de tipul cerut.

Exemple

Exemplul 1: Verificare de tip, cu subclase și null

Un Integer este și Number, și Object. null nu este instanță a niciunui tip.

public class Main {
    public static void main(String[] args) {
        Object[] valori = {"Iași", 42, 3.14, null};
        for (Object v : valori) {
            System.out.println(v + ": String? " + (v instanceof String)
                + ", Number? " + (v instanceof Number)
                + ", Object? " + (v instanceof Object));
        }
    }
}

Rezultat

Iași: String? true, Number? false, Object? true
42: String? false, Number? true, Object? true
3.14: String? false, Number? true, Object? true
null: String? false, Number? false, Object? false

Exemplul 2: Forma veche și forma cu pattern

Ambele metode fac același lucru. Varianta nouă nu mai repetă tipul și nu are conversie manuală. Variabila pattern poate fi folosită chiar în aceeași condiție, după &&.

public class Main {
    static String vechi(Object o) {
        if (o instanceof String) {
            String s = (String) o;
            return "text de " + s.length() + " caractere";
        }
        return "altceva";
    }

    static String nou(Object o) {
        if (o instanceof String s && !s.isBlank()) {
            return "text de " + s.length() + " caractere";
        }
        if (o instanceof Integer n && n > 0) {
            return "număr pozitiv, dublul = " + (n * 2);
        }
        return "altceva";
    }

    public static void main(String[] args) {
        System.out.println(vechi("Suceava"));
        System.out.println(nou("Suceava"));
        System.out.println(nou("   "));
        System.out.println(nou(21));
        System.out.println(nou(-3));
    }
}

Rezultat

text de 7 caractere
text de 7 caractere
altceva
număr pozitiv, dublul = 42
altceva

Exemplul 3: Negație și ieșire timpurie

După if (!(o instanceof Elev e)) return ...;, compilatorul știe că mai jos o este sigur un Elev, deci e poate fi folosită în restul metodei.

record Elev(String nume, double medie) { }

public class Main {
    static String diploma(Object o) {
        if (!(o instanceof Elev e)) {
            return "nu este elev: " + o;
        }
        return e.medie() >= 9.5 ? e.nume() + " primește premiul I" : e.nume() + " primește diplomă de participare";
    }

    public static void main(String[] args) {
        System.out.println(diploma(new Elev("Daria", 9.8)));
        System.out.println(diploma(new Elev("Tudor", 8.4)));
        System.out.println(diploma("Bianca"));
    }
}

Rezultat

Daria primește premiul I
Tudor primește diplomă de participare
nu este elev: Bianca

Greșeli frecvente

  • Faci conversia fără verificare: (String) o aruncă ClassCastException dacă o este, de fapt, un Integer.
  • Folosești variabila pattern unde testul poate să fi eșuat, de exemplu după ||: cannot find symbol.
  • Testezi un tip care nu are cum să se potrivească (String s; s instanceof Integer): incompatible types: String cannot be converted to Integer.

Comenzi înrudite

  • Pattern matching (instanceof și switch): Pattern matching testează tipul (și forma) unui obiect și îi extrage părțile într-un singur pas, în instanceof sau în switch.
  • Record patterns: Un record pattern verifică tipul unui record și îi desface direct componentele în variabile, inclusiv pentru records imbricate.
  • Polimorfism: Polimorfismul înseamnă că același apel (f.arie()) execută metoda clasei reale a obiectului, chiar dacă variabila are tipul superclasei.
  • sealed, permits și non-sealed: O clasă sau interfață sealed își alege explicit subtipurile (permits); fiecare subtip este final, sealed sau non-sealed.