¿Para qué se utiliza el operador 'instanceof' en Java?

163

¿Para qué se instanceofutiliza el operador? He visto cosas como

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

Pero nada de eso tenía sentido para mí. He hecho mi investigación, pero solo encontré ejemplos sin ninguna explicación.

Ben
fuente
38
No hay nada de malo en hacer preguntas aquí, pero si está aprendiendo Java, es posible que desee obtener un libro. Cualquier libro decente de Java tendría la respuesta a esta pregunta y los próximos 1000 que tendrá.
Presidente James K. Polk
Tal operador tiene muchos usos específicos. Esta sería una pregunta específica si solicitara una explicación de uno de los ejemplos que no tiene sentido para usted.
Raedwald
2
Las respuestas a continuación son correctas, sin embargo, tenga en cuenta que instanceof es un operador usado en exceso 9 de cada 10 veces, puede ser reemplazado por un uso adecuado del polimorfismo (no siempre, pero a menudo)
Richard Tingle
Yo iría más lejos que Richard: NUNCA he visto un uso válido de instanceof. Solo es útil para hacks rápidos además de código mal diseñado. Si no te gusta la OOP, escribe en otro idioma (hay muchos). ¡Solo di "no" a la instancia!
Scott Biggs
55
@ScottBiggs ¿Hay una buena alternativa para instanceofanular equals?
Ben Aaronson

Respuestas:

228

instanceofLa palabra clave es un operador binario utilizado para probar si un objeto (instancia) es un subtipo de un tipo dado.

Imagina:

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

Imagine un dog objeto , creado con Object dog = new Dog(), entonces:

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

Sin embargo, con Object animal = new Animal();,

animal instanceof Dog // false

porque Animales un supertipo de Dogy posiblemente menos "refinado".

Y,

dog instanceof Cat // does not even compile!

Esto se debe a Dogque no es un subtipo ni un supertipo de Cat, y tampoco lo implementa.

Tenga en cuenta que la variable utilizada para dogarriba es de tipo Object. Esto es para mostrar que instanceofes una operación en tiempo de ejecución y nos lleva a un / el caso de uso: reaccionar de manera diferente en función de un tipo de objetos en tiempo de ejecución .

Cosas a tener en cuenta: expressionThatIsNull instanceof Tes falso para todos los tipos T.

Feliz codificación

Caché Staheli
fuente
14
Acabo de intentarlo Object dog = new Dog(); System.out.println(dog instanceof Cat);. Esto compila muy bien e imprime false. El compilador no puede determinar en el momento de la compilación que dogno puede ser un gato (según las reglas en el JLS)
Erwin Bolwidt
@ErwinBolwidt Cometiste un error cuando lo intentaste. Para cualquiera que se pregunte: JLS Sección 15.20.2 es la que está buscando. Para un ejemplo mínimo no laboral:boolean b = "foo" instanceof Integer;
Felix S
3
@FelixS Debe leer la respuesta nuevamente. La respuesta es sobre Object indirect = ...; if (indirect instanceof Something). No se trata de lo if (literal instanceof Something)que parece estar asumiendo.
Erwin Bolwidt
1
@ErwinBolwidt Oh, claro, debo haberme saltado la Object dogparte. ¡Culpa mía!
Felix S
dog instanceof Cat // does not even compile!(porque es una clase) Si Catfuera una interfaz, entonces se compilaría.
Hamza Belmellouki
44

Es un operador que devuelve verdadero si el lado izquierdo de la expresión es una instancia del nombre de la clase en el lado derecho.

Piensa en ello de esta manera. Digamos que todas las casas en su cuadra fueron construidas con los mismos planos. Diez casas (objetos), un conjunto de planos (definición de clase).

instanceofes una herramienta útil cuando tienes una colección de objetos y no estás seguro de cuáles son. Digamos que tienes una colección de controles en un formulario. Desea leer el estado marcado de las casillas de verificación que haya allí, pero no puede pedirle a un objeto antiguo simple su estado marcado. En cambio, vería si cada objeto es una casilla de verificación, y si lo es, conviértalo en una casilla de verificación y verifique sus propiedades.

if (obj instanceof Checkbox)
{
    Checkbox cb = (Checkbox)obj;
    boolean state = cb.getState();
}
Michael Petrotta
fuente
15
Es decir, el uso instanceofpuede hacer que sea seguro bajarlos.
Raedwald
29

Como se describe en este sitio :

El instanceofoperador se puede usar para probar si un objeto es de un tipo específico ...

if (objectReference instanceof type)

Un ejemplo rápido:

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

Sin embargo, la aplicación instanceofen una variable / expresión de referencia nula devuelve falso.

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

Dado que una subclase es un 'tipo' de su superclase, puede usar el instanceofpara verificar esto ...

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

¡Espero que esto ayude!

sombra de fuego52
fuente
15

Este operador le permite determinar el tipo de un objeto. Devuelve unboolean valor.

Por ejemplo

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

la salida es:

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

Si sourcees una objectvariable, instanceofes una forma de verificar si es Buttono no.

Daniel A. White
fuente
5

Como se menciona en otras respuestas, el uso típico canónico instanceofes para verificar si un identificador se refiere a un tipo más específico. Ejemplo:

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
}

Sin embargo, tenga en cuenta que el tipo de la expresión de la izquierda debe ser un tipo primario de la expresión de la derecha (vea JLS 15.20.2 y Java Puzzlers, # 50, pp114 ). Por ejemplo, lo siguiente no se compilará:

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

Esto no se compila con el mensaje:

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

Como Testno es una clase padre de String. OTOH, esto se compila perfectamente e imprime falsecomo se esperaba:

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
fuente
¡Gracias por vincularte a la especificación!
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
fuente
1

Se puede utilizar como taquigrafía en la verificación de igualdad.

Entonces este código

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

Se puede escribir como

if(ob instanceOf ClassA) {
}
mirmdasif
fuente
1

La mayoría de las personas han explicado correctamente el "Qué" de esta pregunta, pero nadie explicó "Cómo" correctamente.

Así que aquí hay una ilustración simple:

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

Salidas:

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

La razón del error del compilador al comparar scon StringBuffer se explica bien en los documentos :

Puede usarlo para probar si un objeto es una instancia de una clase, una instancia de una subclase o una instancia de una clase que implementa una interfaz particular.

lo que implica que el LHS debe ser una instancia de RHS o de una Clase que implemente RHS o extienda RHS.

¿Cómo usar use instanceof entonces?
Dado que cada Clase extiende Objeto, la conversión de tipos de LHS a objeto siempre funcionará a su 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");

Salidas:

Not an instance of StringBuffer
sziraqui
fuente
En el último ejemplo, ¿por qué devuelve "No es una instancia de StringBuffer"? ¿Ya que escribiste s a Object en LHS y comprobaste si es una instancia de RHS if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //shouldn't this be true, ya que estamos tipeando s a Object?
sofs1
Porque s es una referencia al objeto String (Java emplea un polimorfismo dinámico a diferencia de C ++) y String no es una subclase de StringBuffer.
sziraqui
0

La instancia de la palabra clave es útil cuando desea conocer la instancia de un objeto en particular.

Suponga que es una excepción de lanzamiento y cuando tiene captura, realice una operación personalizada de suma y luego continúe nuevamente según su lógica (lanzamientos o registro, etc.)

Ejemplo: 1) El usuario creó la excepción personalizada "InvalidExtensionsException" y la arrojó según la lógica

2) Ahora en catch block catch (Exception e) {realice la lógica de suma si el tipo de excepción es "InvalidExtensionsException"

InvalidExtensionsException InvalidException =(InvalidExtensionsException)e;

3) Si no está verificando la instancia y el tipo de excepción es la excepción de puntero nulo, su código se romperá.

Por lo tanto, su lógica debe estar dentro de la instancia de if (e instanceof InvalidExtensionsException) {InvalidExtensionsException InvalidException = (InvalidExtensionsException) e; }

El ejemplo anterior es una práctica de codificación incorrecta. Sin embargo, este ejemplo le ayuda a comprender el uso de la instancia.

Vaquar Khan
fuente
0

La mejor explicación es jls . Siempre trate de verificar lo que dice la fuente. Allí obtendrá la mejor respuesta y mucho más. Reproduciendo algunas partes aquí:

El tipo del operando RelationalExpression del operador instanceof debe ser un tipo de referencia o el tipo nulo; de lo contrario, se produce un error en tiempo de compilación.

Es un error en tiempo de compilación si el ReferenceType mencionado después del operador instanceof no denota un tipo de referencia que sea reificable (§4.7).

Si una conversión (§15.16) de RelationalExpression to ReferenceType sería rechazada como un error en tiempo de compilación, entonces la instancia de expresión relacional también produce un error en tiempo de compilación. En tal situación, el resultado de la instancia de expresión nunca podría ser cierto.

nanosoft
fuente
0

El instanceofoperador java se utiliza para probar si el objeto es una instancia del tipo especificado (clase, subclase o interfaz).

La instancia de java también se conoce como tipo, comparison operatorya que compara la instancia con el tipo. Devuelve ya sea trueo false. Si aplicamos el instanceofoperador con cualquier variable que tenga nullvalor, devuelve false.

Desde JDK 14+ que incluye JEP 305 también podemos hacer "Pattern Matching" parainstanceof

Los patrones básicamente prueban que un valor tiene un cierto tipo y pueden extraer información del valor cuando tiene el tipo correspondiente. La coincidencia de patrones permite una expresión más clara y eficiente de la lógica común en un sistema, es decir, la eliminación condicional de componentes de los objetos.

Antes de Java 14

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

Mejoras de Java 14

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

También podemos combinar la verificación de tipo y otras condiciones juntas

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

El uso de la coincidencia de patrones instanceofdebería reducir el número total de conversiones explícitas en los programas Java.

PD : instanceOfsolo coincidirá cuando el objeto no sea nulo, luego solo se le puede asignar str.

Bhanu Hoysala
fuente
-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
fuente
1
No publique respuestas de código solo en StackOverflow. Por favor, continúe y agregue una explicación.
L. Guthardt
-2

Ejemplo de código muy simple:

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

Ten cuidado aquí. En el ejemplo anterior, si Class1 es Object, la primera comparación siempre será verdadera. Entonces, al igual que con las excepciones, ¡el orden jerárquico es importante!

mjuarez
fuente
-2

Puede usar Map para hacer una mayor abstracción en caso de

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

Luego, al hacer que dicho mapa agregue alguna acción:

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

Luego, al tener un Objeto de tipo desconocido, puede obtener una acción específica de ese mapa:

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

El operador instanceof se usa para verificar si el objeto es una instancia del tipo especificado. (clase o subclase o interfaz).

La instancia de también se conoce como operador de comparación de tipos porque compara la instancia con el tipo. Devuelve verdadero o falso.

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

Si aplicamos el operador instanceof con cualquier variable que tenga un valor nulo, devuelve falso.

Viraj Pai
fuente