Operador instanceof do Java
Verifique o tipo em tempo de execução com o operador instanceof e use pattern matching para instanceof no Java.
instanceof faz uma pergunta em tempo de execução: "esta referência é realmente um T (ou um subtipo de T)?" A resposta é um boolean, e a forma moderna com pattern matching também vincula o valor a uma variável tipada em uma única etapa, eliminando a necessidade de um cast separado.
É a ferramenta que você usa sempre que tem uma referência polimórfica e precisa saber qual tipo concreto ela realmente é — tipicamente dentro de equals, ao percorrer uma estrutura de dados heterogênea, ou ao trabalhar com hierarquias seladas.
A forma básica
A sintaxe clássica é expression instanceof Type:
Object o = "hello";
if (o instanceof String) {
String s = (String) o;
System.out.println(s.length());
}A verificação retorna true se o se refere a uma String ou qualquer subtipo, e false se o é null ou aponta para um tipo diferente de objeto. null instanceof Anything é sempre false — uma garantia pequena mas útil.
Pattern matching para instanceof
Desde o Java 16, instanceof aceita um type pattern que declara uma variável vinculada ao tipo reduzido na mesma expressão:
if (o instanceof String s) {
System.out.println(s.length()); // no cast needed
}Se a verificação for bem-sucedida, s está no escopo e já tipado como String. Se falhar, s não está no escopo. O cast desaparece, a redundância desaparece, e você não pode acidentalmente fazer cast de algo que a verificação rejeitou.
Escopo da variável vinculada
A variável vinculada está no escopo onde o compilador pode provar que a verificação foi bem-sucedida. Isso inclui o ramo do if, mas também flui através de && e para a negação do 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 returnEsse segundo padrão é especialmente útil para código no estilo de cláusula guarda — reduza o tipo, saia se não houver correspondência, e use o nome vinculado livremente abaixo.
O lado oposto é ||: o vínculo não flui através dele, porque o lado direito é executado precisamente quando a verificação falhou. o instanceof String s || s.length() > 0 não compila — s não está no escopo à direita do ||.
Restrições sobre o tipo alvo
O compilador rejeita verificações que ele pode provar serem impossíveis. "hello" instanceof Integer nem mesmo compila, porque String e Integer não são relacionados. Isso captura erros de digitação e resíduos de refatoração em tempo de compilação, e não em tempo de execução.
Ele também rejeita upcasts que não podem falhar: Object o = ...; if (o instanceof Object) {} é marcado como redundante.
Em switch
O mesmo mecanismo de pattern matching está disponível no switch, onde realmente brilha em hierarquias seladas:
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";
};
}Com um tipo selado como seletor, você pode remover o default e o compilador exigirá um caso para cada subtipo permitido — combine isso com sealed classes para obter análise de casos exaustiva.
Quando usar — e quando não usar
Use instanceof quando o tipo é genuinamente desconhecido e a resposta muda o comportamento: implementando equals, processando hierarquias seladas de tagged-union, percorrendo nós de AST. Não o use como substituto para polimorfismo adequado — uma cadeia de if (x instanceof A) ... else if (x instanceof B) ... sobre uma hierarquia aberta é geralmente um sinal de que um método virtual no tipo faria o trabalho melhor.
Um exemplo prático
O que vem a seguir
instanceof é um dos vários métodos aos quais todo objeto Java responde. O próximo capítulo amplia a visão para examinar o conjunto completo — java.lang.Object, a classe raiz que todo tipo estende silenciosamente, e os métodos que você herda dela independentemente de querer ou não. Continue para Java Object class.