W3docs

Operatore instanceof in Java

Verifica il tipo a runtime di un oggetto con instanceof e usa il pattern matching per instanceof in Java.

instanceof pone una domanda a runtime: "questo riferimento è effettivamente un T (o un sottotipo di T)?" La risposta è un boolean, e la moderna forma con pattern matching può anche legare il valore a una variabile tipizzata in un unico passaggio, eliminando la necessità di un cast separato.

È lo strumento da utilizzare quando si ha un riferimento polimorfico e si deve determinare quale tipo concreto sia davvero — tipicamente all'interno di equals, quando si attraversa una struttura dati eterogenea, o quando si lavora con gerarchie sealed.

La forma base

La sintassi classica è expression instanceof Type:

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

Il controllo restituisce true se o fa riferimento a una String o a un suo sottotipo, e false se o è null o punta a un tipo diverso. null instanceof Anything è sempre false — una garanzia piccola ma utile.

Pattern matching per instanceof

A partire da Java 16, instanceof accetta un type pattern che dichiara una variabile legata al tipo ristretto nella stessa espressione:

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

Se il controllo ha successo, s è in scope ed è già tipizzata come String. Se fallisce, s non è in scope. Il cast è sparito, la ridondanza è sparita, e non è possibile eseguire accidentalmente il cast di qualcosa che il controllo ha rifiutato.

Scope della variabile legata

La variabile legata è in scope ovunque il compilatore possa dimostrare che il controllo ha avuto successo. Questo include il ramo if, ma si propaga anche attraverso && e nella negazione dell'if:

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

Il secondo pattern è particolarmente utile per il codice in stile guard-clause — si restringe il tipo, si esce se non corrisponde, e si usa liberamente il nome legato più in basso.

Il lato opposto è ||: il binding non si propaga attraverso di esso, perché il lato destro viene eseguito proprio quando il controllo è fallito. o instanceof String s || s.length() > 0 non compila — s non è in scope a destra di ||.

Restrizioni sul tipo target

Il compilatore rifiuta i controlli che può dimostrare essere impossibili. "hello" instanceof Integer non compilerà nemmeno, perché String e Integer non sono correlati. Questo intercetta refusi ed errori di refactoring a tempo di compilazione anziché a runtime.

Rifiuta anche gli upcast che non possono fallire: Object o = ...; if (o instanceof Object) {} viene segnalato come ridondante.

In switch

La stessa macchina di pattern matching è disponibile in switch, dove brilla davvero su gerarchie sealed:

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";
  };
}

Con un tipo sealed come selettore, è possibile eliminare il default e il compilatore richiederà un caso per ogni sottotipo consentito — abbinalo alle sealed classes per ottenere un'analisi dei casi esaustiva.

Quando usarlo — e quando non farlo

Usa instanceof quando il tipo è genuinamente sconosciuto e la risposta cambia il comportamento: implementando equals, elaborando gerarchie sealed a unione etichettata, attraversando nodi AST. Non usarlo come sostituto del polimorfismo corretto — una catena di if (x instanceof A) ... else if (x instanceof B) ... su una gerarchia aperta è solitamente un segnale che un metodo virtuale sul tipo farebbe il lavoro meglio.

Un esempio pratico

java— editable, runs on the server

Cosa c'è dopo

instanceof è uno dei vari metodi a cui ogni oggetto Java risponde. Il prossimo capitolo allarga la prospettiva per esaminare l'intero insieme — java.lang.Object, la classe radice che ogni tipo estende silenziosamente, e i metodi che si ereditano da essa che lo si voglia o meno. Continua con la classe Object di Java.

Esercitati

Pratica
Cosa risparmia il pattern matching per `instanceof` (`if (o instanceof String s)`) rispetto alla forma classica?
Cosa risparmia il pattern matching per `instanceof` (`if (o instanceof String s)`) rispetto alla forma classica?
Was this page helpful?