Para que é utilizado o operador 'instanceof' em Java?

163

Para que é instanceofutilizado o operador? Eu já vi coisas como

if (source instanceof Button) {
    //...
} else {
    //...
}

Mas nada disso fazia sentido para mim. Eu fiz minha pesquisa, mas criei apenas exemplos sem explicações.

Ben
fonte
38
Não há nada errado em fazer perguntas aqui, mas se você estiver aprendendo Java, poderá obter um livro. Qualquer livro Java decente teria a resposta para esta pergunta e as próximas 1000 que você terá.
Presidente James K. Polk
Esse operador tem muitos usos específicos. Essa seria uma pergunta específica se solicitasse uma explicação de um dos exemplos que não faziam sentido para você.
Raedwald 23/08
2
As respostas abaixo estão corretos, no entanto, note que instanceof é um operador em demasia 9 vezes fora de 10 que pode ser substituído por um uso adequado de polimorfismo (nem sempre, mas muitas vezes)
Richard Tingle
Eu iria um pouco além de Richard: nunca vi um uso válido de instanceof. Só é útil para hacks rápidos em cima de códigos mal projetados. Se você não gosta de POO, escreva em outro idioma (há bastante). Apenas diga "não" para instância!
Scott Biggs
5
@ScottBiggs Existe uma boa alternativa para instanceofsubstituir equals?
Ben Aaronson

Respostas:

228

instanceofA palavra-chave é um operador binário usado para testar se um objeto (instância) é um subtipo de um determinado tipo.

Imagine:

interface Domestic {}
class Animal {}
class Dog extends Animal implements Domestic {}
class Cat extends Animal implements Domestic {}

Imagine um dog objeto criado com Object dog = new Dog(), então:

dog instanceof Domestic // true - Dog implements Domestic
dog instanceof Animal   // true - Dog extends Animal
dog instanceof Dog      // true - Dog is Dog
dog instanceof Object   // true - Object is the parent type of all objects

No entanto, com Object animal = new Animal();,

animal instanceof Dog // false

porque Animalé um supertipo Doge possivelmente menos "refinado".

E,

dog instanceof Cat // does not even compile!

Isso ocorre porque Dognão é um subtipo nem um supertipo de Cat, e também não o implementa.

Observe que a variável usada dogacima é do tipo Object. Isso é para mostrar que instanceofé uma operação de tempo de execução e nos leva a um / ao caso de uso: reagir de maneira diferente com base no tipo de objeto no tempo de execução .

O que deve ser observado: expressionThatIsNull instanceof Té falso para todos os tipos T.

Feliz codificação.

Cache Staheli
fonte
14
Eu apenas tentei - Object dog = new Dog(); System.out.println(dog instanceof Cat);. Isso compila muito bem e imprime false. O compilador não é permitido para determinar em tempo de compilação que dognão pode ser um gato (conforme as regras nas JLS)
Erwin Bolwidt
@ErwinBolwidt Você cometeu um erro ao tentar isso. Para quem se pergunta: a Seção 15.20.2 do JLS é a que você está procurando. Para um exemplo mínimo não-útil:boolean b = "foo" instanceof Integer;
Felix S
3
@FelixS Você precisa ler a resposta novamente. A resposta é sobre Object indirect = ...; if (indirect instanceof Something). Não é if (literal instanceof Something)como você parece estar assumindo.
Erwin Bolwidt
1
@ErwinBolwidt Oh, certo, eu devo ter pulado a Object dogparte. Foi mal!
Felix S
dog instanceof Cat // does not even compile!(porque é uma classe). Se Catfosse uma interface, ela seria compilada.
Hamza Belmellouki 13/06/19
44

É um operador que retorna true se o lado esquerdo da expressão for uma instância do nome da classe no lado direito.

Pense nisso desta maneira. Digamos que todas as casas do seu quarteirão foram construídas com os mesmos projetos. Dez casas (objetos), um conjunto de plantas (definição de classe).

instanceofé uma ferramenta útil quando você tem uma coleção de objetos e não tem certeza do que eles são. Digamos que você tenha uma coleção de controles em um formulário. Você deseja ler o estado marcado de qualquer caixa de seleção existente, mas não pode solicitar a um objeto antigo simples o estado marcado. Em vez disso, você veria se cada objeto é uma caixa de seleção e, se for, lança-o em uma caixa de seleção e marque suas propriedades.

if (obj instanceof Checkbox)
{
    Checkbox cb = (Checkbox)obj;
    boolean state = cb.getState();
}
Michael Petrotta
fonte
15
Ou seja, usar instanceofpode torná-lo seguro para fazer o downcast.
Raedwald 23/08/13
29

Conforme descrito neste site :

O instanceofoperador pode ser usado para testar se um objeto é de um tipo específico ...

if (objectReference instanceof type)

Um exemplo rápido:

String s = "Hello World!"
return s instanceof String;
//result --> true

No entanto, aplicar instanceofem uma variável / expressão de referência nula retorna false.

String s = null;
return s instanceof String;
//result --> false

Como uma subclasse é um 'tipo' de sua superclasse, você pode usar o instanceofpara verificar isso ...

class Parent {
    public Parent() {}
}

class Child extends Parent {
    public Child() {
        super();
    }
}

public class Main {
    public static void main(String[] args) {
        Child child = new Child();
        System.out.println( child instanceof Parent );
    }
}
//result --> true

Eu espero que isso ajude!

fireshadow52
fonte
15

Este operador permite determinar o tipo de um objeto. Retorna um booleanvalor.

Por exemplo

package test;

import java.util.Date;
import java.util.Map;
import java.util.HashMap;

public class instanceoftest
{
    public static void main(String args[])
    {
        Map m=new HashMap();
        System.out.println("Returns a boolean value "+(m instanceof Map));
        System.out.println("Returns a boolean value "+(m instanceof HashMap));
        System.out.println("Returns a boolean value "+(m instanceof Object));
        System.out.println("Returns a boolean value "+(m instanceof Date));
    }
} 

a saída é:

Returns a boolean value true
Returns a boolean value true
Returns a boolean value true
Returns a boolean value false
Purendra Agrawal
fonte
14

Se sourceé uma objectvariável, instanceofé uma maneira de verificar se é Buttonou não.

Daniel A. White
fonte
4

Conforme mencionado em outras respostas, o uso típico canônico instanceofé para verificar se um identificador está se referindo a um tipo mais específico. Exemplo:

Object someobject = ... some code which gets something that might be a button ...
if (someobject instanceof Button) {
    // then if someobject is in fact a button this block gets executed
} else {
    // otherwise execute this block
}

Observe, no entanto, que o tipo da expressão à esquerda deve ser um tipo pai da expressão à direita (consulte JLS 15.20.2 e Java Puzzlers, # 50, pp114 ). Por exemplo, o seguinte falhará ao compilar:

public class Test {
    public static void main(String [] args) {
        System.out.println(new Test() instanceof String); // will fail to compile
    }
}

Isso falha ao compilar com a mensagem:

Test.java:6: error: inconvertible types
        System.out.println(t instanceof String);
                       ^
  required: String
  found:    Test
1 error

Como Testnão é uma classe pai de String. OTOH, isso compila perfeitamente e imprime falseconforme o esperado:

public class Test {
    public static void main(String [] args) {
        Object t = new Test();
        // compiles fine since Object is a parent class to String
        System.out.println(t instanceof String); 
    }
}
Adam Parkin
fonte
Obrigado por vincular as especificações!
jpaugh
1
public class Animal{ float age; }

public class Lion extends Animal { int claws;}

public class Jungle {
    public static void main(String args[]) {

        Animal animal = new Animal(); 
        Animal animal2 = new Lion(); 
        Lion lion = new Lion(); 
        Animal animal3 = new Animal(); 
        Lion lion2 = new Animal();   //won't compile (can't reference super class object with sub class reference variable) 

        if(animal instanceof Lion)  //false

        if(animal2 instanceof Lion)  //true

        if(lion insanceof Lion) //true

        if(animal3 instanceof Animal) //true 

    }
}
bangbang
fonte
1

Pode ser usado como um atalho na verificação de igualdade.

Então esse código

if(ob != null && this.getClass() == ob.getClass) {
}

Pode ser escrito como

if(ob instanceOf ClassA) {
}
mirmdasif
fonte
1

A maioria das pessoas explicou corretamente o "O quê" desta pergunta, mas ninguém explicou o "Como" corretamente.

Então, aqui está uma ilustração simples:

String s = new String("Hello");
if (s instanceof String) System.out.println("s is instance of String"); // True
if (s instanceof Object) System.out.println("s is instance of Object"); // True
//if (s instanceof StringBuffer) System.out.println("s is instance of StringBuffer"); // Compile error
Object o = (Object)s;
if (o instanceof StringBuffer) System.out.println("o is instance of StringBuffer"); //No error, returns False
else System.out.println("Not an instance of StringBuffer"); // 
if (o instanceof String) System.out.println("o is instance of String"); //True

Saídas:

s is instance of String
s is instance of Object
Not an instance of StringBuffer
o is instance of String

O motivo do erro do compilador ao comparar scom o StringBuffer é bem explicado nos documentos :

Você pode usá-lo para testar se um objeto é uma instância de uma classe, uma instância de uma subclasse ou uma instância de uma classe que implementa uma interface específica.

que implica o LHS deve ser uma instância do RHS ou de uma classe que implemente o RHS ou estenda o RHS.

Como usar use instanceof então?
Como toda classe estende um objeto, o LHS de conversão de tipo para objeto sempre funcionará a seu favor:

String s = new String("Hello");
if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //No compiler error now :)
else System.out.println("Not an instance of StringBuffer");

Saídas:

Not an instance of StringBuffer
sziraqui
fonte
No último exemplo, por que está retornando "Não é uma instância do StringBuffer"? Como você digitou s para Objeto no LHS e verificou se é uma instância do RHS if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //shouldn't this be true, já que estamos digitando s para Objeto?
precisa saber é o seguinte
Como s é uma referência ao objeto String (Java emprega polimorfismo dinâmico diferente de C ++) e String não é uma subclasse de StringBuffer.
Sziraqui 13/09/19
0

O operador instanceof compara um objeto com um tipo especificado. Você pode usá-lo para testar se um objeto é uma instância de uma classe, uma instância de uma subclasse ou uma instância de uma classe que implementa uma interface específica.

http://download.oracle.com/javase/tutorial/java/nutsandbolts/op2.html

Benjamin Udink ten Cate
fonte
0

A instância da palavra-chave é útil quando você deseja conhecer a instância de um objeto específico.

Suponha que você esteja lançando uma exceção e quando tiver capturado, execute a operação personalizada de soma e continue novamente conforme sua lógica (lances ou log etc.)

Exemplo: 1) O usuário criou a exceção personalizada "InvalidExtensionsException" e a lança conforme a lógica

2) Agora, no bloco catch catch (Exceção e) {execute a lógica da soma se o tipo de exceção for "InvalidExtensionsException"

InvalidExtensionsException InvalidException =(InvalidExtensionsException)e;

3) Se você não estiver verificando a instância e o tipo de exceção for Exceção de ponteiro nulo, seu código será interrompido.

Portanto, sua lógica deve estar dentro da instância de if (instância de InvalidExtensionsException) {InvalidExtensionsException InvalidException = (InvalidExtensionsException) e; }

O exemplo acima é uma prática incorreta de codificação. No entanto, este exemplo ajuda a entender o uso da instância dele.

vaquar khan
fonte
0

A melhor explicação é jls . Sempre tente verificar o que a fonte diz. Lá você obterá a melhor resposta e muito mais. Reproduzindo algumas partes aqui:

O tipo do operando RelationalExpression do operador instanceof deve ser um tipo de referência ou o tipo nulo; caso contrário, ocorrerá um erro em tempo de compilação.

É um erro em tempo de compilação se o ReferenceType mencionado após a instância do operador não indicar um tipo de referência que seja reificável (§4.7).

Se uma conversão (§15.16) da RelationalExpression para o ReferenceType fosse rejeitada como um erro em tempo de compilação, a instância da expressão relacional também produzirá um erro em tempo de compilação. Em tal situação, o resultado da instância da expressão nunca poderia ser verdadeiro.

nanosoft
fonte
0

O instanceofoperador java é usado para testar se o objeto é uma instância do tipo especificado (classe ou subclasse ou interface).

A instanceof em java também é conhecida como tipo comparison operator, pois compara a instância com o tipo. Retorna trueou false. Se aplicarmos o instanceofoperador com qualquer variável que tenha nullvalor, ela retornará false.

Do JDK 14+, que inclui o JEP 305 , também podemos fazer "Correspondência de Padrões" parainstanceof

Os padrões testam basicamente que um valor tem um determinado tipo e podem extrair informações do valor quando ele possui o tipo correspondente. A correspondência de padrões permite uma expressão mais clara e eficiente da lógica comum em um sistema, ou seja, a remoção condicional de componentes dos objetos.

Antes do Java 14

if (obj instanceof String) {
    String str = (String) obj; // need to declare and cast again the object
    .. str.contains(..) ..
}else{
     str = ....
}

Aprimoramentos do Java 14

if (!(obj instanceof String str)) {
    .. str.contains(..) .. // no need to declare str object again with casting
} else {
    .. str....
}

Também podemos combinar a verificação de tipo e outras condições

if (obj instanceof String str && str.length() > 4) {.. str.contains(..) ..}

O uso da correspondência de padrões em instanceofdeve reduzir o número geral de transmissões explícitas nos programas Java.

PS : instanceOfcorresponderá apenas quando o objeto não for nulo, e somente poderá ser atribuído a ele str.

Bhanu Hoysala
fonte
-1
class Test48{
public static void main (String args[]){
Object Obj=new Hello();
//Hello obj=new Hello;
System.out.println(Obj instanceof String);
System.out.println(Obj instanceof Hello);
System.out.println(Obj instanceof Object);
Hello h=null;
System.out.println(h instanceof Hello);
System.out.println(h instanceof Object);
}
}  
sajid sadiq
fonte
1
Não poste respostas apenas de código no StackOverflow. Por favor, vá em frente e adicione uma explicação.
Guthardt L.
-2

Exemplo de código muito simples:

If (object1 instanceof Class1) {
   // do something
} else if (object1 instanceof Class2) {
   // do something different
}

Tenha cuidado aqui. No exemplo acima, se Class1 for Object, a primeira comparação será sempre verdadeira. Portanto, assim como as exceções, a ordem hierárquica é importante!

mjuarez
fonte
-2

Você pode usar o Map para obter uma abstração mais alta na instância de

private final Map<Class, Consumer<String>> actions = new HashMap<>();

Em seguida, fazer com que esse mapa adicione alguma ação a ele:

actions.put(String.class, new Consumer<String>() {
        @Override
        public void accept(String s) {
           System.out.println("action for String");       
        }
    };

Depois de ter um objeto de tipo desconhecido, você pode obter ações específicas desse mapa:

actions.get(someObject).accept(someObject)
tomekl007
fonte
-2

O operador instanceof é usado para verificar se o objeto é uma instância do tipo especificado. (classe ou subclasse ou interface).

A instanceof também é conhecida como operador de comparação de tipos, porque compara a instância com o tipo. Retorna verdadeiro ou falso.

class Simple1 {  
public static void main(String args[]) {  
Simple1 s=new Simple1();  
System.out.println(s instanceof Simple1); //true  
}  
}  

Se aplicarmos o operador instanceof com qualquer variável que tenha valor nulo, ele retornará false.

Viraj Pai
fonte