java: Class.isInstance vs Class.isAssignableFrom

232

Dejen clazzser algunos Classy objsean algunos Object.

Es

clazz.isAssignableFrom(obj.getClass())

siempre lo mismo que

clazz.isInstance(obj)

?

Si no es así, ¿cuáles son las diferencias?

Albert
fuente
26
si obj == nulo, el segundo devuelve falso, el primero no. ;)
Peter Lawrey
21
@PeterLawrey, el primero arrojará un NullPointerExceptionif obj == null.
ryvantage
Encontré alguna respuesta con muestras de hrere: mytechnotes.biz/2012/07/…
Paramesh Korrakuti
44
Para los lectores: estás a punto de entrar en un agujero negro profundo y oscuro del que nunca escaparás. Las diferencias son infinitas. Ríndete ahora mientras puedas: stackoverflow.com/q/496928/1599699
Andrew
@ParameshKorrakuti el nombre de dominio está cambiando a tshikatshikaaa.blogspot.com/2012/07/…
Jérôme Verstrynge

Respuestas:

222

clazz.isAssignableFrom(Foo.class)será verdadero siempre que la clase representada por el clazzobjeto sea una superclase o superinterfaz de Foo.

clazz.isInstance(obj)será verdadero siempre que el objeto objsea ​​una instancia de la clase clazz.

Es decir:

clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj)

siempre es cierto siempre clazzy cuando no objsean nulos.

uckelman
fuente
3
esto pierde el caso donde Foo es lo mismo que clazz, en cuyo caso devuelve verdadero: la respuesta más votada de Pauls a continuación corrige esto
ruibarbo
3
Estoy de acuerdo en que cuando clazz es un Foo, entonces clazz.isAssignableFrom (Foo.class) es cierto. ¿Dónde dije lo contrario?
uckelman
55
@Gili Esto no es lo que dijo uckelman. Por favor, vuelva a leer su respuesta.
Puce
2
Byte b = 3; Comparable.class.isAssignableFrom(b.getClass()) == Comparable.class.isInstance(b)); -> es cierto también para las interfaces.
Puce
1
Técnico: si objes nullasí clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj), arrojará un NullPointerExceptiony no volverá true.
Andrew Macheret
196

Ambas respuestas están en el estadio pero ninguna es una respuesta completa.

MyClass.class.isInstance(obj)es para verificar una instancia. Devuelve verdadero cuando el parámetro obj no es nulo y se puede convertir MyClasssin generar a ClassCastException. En otras palabras, obj es una instancia de MyClasso sus subclases.

MyClass.class.isAssignableFrom(Other.class)devolverá true si MyClasses el mismo que, o una superclase o superinterfaz de, Other. Otherpuede ser una clase o una interfaz. Responde verdadero si Otherse puede convertir a a MyClass.

Un pequeño código para demostrar:

public class NewMain
{
    public static void main(String[] args)
    {
        NewMain nm = new NewMain();
        nm.doit();
    }

    class A { }

    class B extends A { }

    public void doit()
    {
        A myA = new A();
        B myB = new B();
        A[] aArr = new A[0];
        B[] bArr = new B[0];

        System.out.println("b instanceof a: " + (myB instanceof A)); // true
        System.out.println("b isInstance a: " + A.class.isInstance(myB)); //true
        System.out.println("a isInstance b: " + B.class.isInstance(myA)); //false
        System.out.println("b isAssignableFrom a: " + A.class.isAssignableFrom(B.class)); //true
        System.out.println("a isAssignableFrom b: " + B.class.isAssignableFrom(A.class)); //false
        System.out.println("bArr isInstance A: " + A.class.isInstance(bArr)); //false
        System.out.println("bArr isInstance aArr: " + aArr.getClass().isInstance(bArr)); //true
        System.out.println("bArr isAssignableFrom aArr: " + aArr.getClass().isAssignableFrom(bArr.getClass())); //true
    }
}
Pablo
fuente
10
¿Por qué en su ejemplo "b isAssignableFrom a:" pero el código es A.class.isAssignableFrom(B.class)? Confundí por la salida :)
Roman Truba
44
ummm ... en todos sus ejemplos "instanceOf" devuelve verdadero iff "isAssignableFrom" devuelve verdadero ... No veo la diferencia de esta manera.
Desarrollador de Android
2
Tenga cuidado de que el texto impreso no coincida con el código y puede ser confuso ... Ejemplo: "System.out.println (" b isAssignableFrom a: "+ A.class.isAssignableFrom (B.class));"
Polster
21
@Paul La respuesta, como es, no es útil, porque el lector se pregunta "¿cuál es la diferencia entre un objeto que es una instancia de una subclase de una clase y el tipo de objeto que es convertible a la clase?" Seguramente, puede ver que le ha dejado al lector tantas preguntas después de leer su respuesta como cuando llegó a esta página. Una mejor respuesta en realidad explicaría la diferencia (o falta de ella). Si no hay diferencia, la respuesta debe indicar directamente: "no hay diferencia práctica".
Aleksandr Dubinsky
2
Más importante aún, el lector se pregunta qué diablos usar para sus propósitos. De acuerdo con los comentarios en la pregunta, isAssignableFrom()arroja un a NullPointerExceptionsi el objeto es nulo, mientras que isInstance()solo devuelve falso. Esa es la verdadera respuesta.
Andrew
6

Creo que el resultado para esos dos debería ser siempre el mismo. La diferencia es que necesita una instancia de la clase para usar isInstancepero solo el Classobjeto para usar isAssignableFrom.

ColinD
fuente
Esto no es 100% cierto. Comparable.class.isAssignableFrom(Byte.class) == truepero Byte.class.isInstance(Comparable.class) == false. En otras palabras, isInstance()no es simétrico para interfaces, solo para subclases.
Gili
66
@Gili: Te has equivocado un poco allí. Byte.class.isInstance(Comparable.class)es falso porque un Classobjeto no es una instancia de Byte. La comparación correcta con Comparable.class.isAssignableFrom(Byte.class)es Comparable.class.isInstance((byte) 1), lo cual es cierto.
ColinD
1
Estoy en desacuerdo. Si busca el Javadoc Byte, descubrirá que se extiende Numbery es una clase. (byte) 1No es equivalente a Byte. El primero es un primitivo. Este último es una clase.
Gili
2
@Gili: Autoboxing convierte primitivo byteen Byteporque el tipo de parámetro de isInstancees Object.
ColinD
2
Bueno. Mi punto original era que las llamadas no son exactamente simétricas entre sí, pero al volver a leer su respuesta, nunca hizo esta afirmación, por lo que tiene razón.
Gili
6

Por brevedad, podemos entender estas dos API como a continuación:

  1. X.class.isAssignableFrom(Y.class)

Si Xy Yson la misma clase, o Xes Yla superclase o la super interfaz, devuelve verdadero, de lo contrario, falso.

  1. X.class.isInstance(y)

Say yes una instancia de clase Y, si Xy Yson la misma clase, o Xes Yla superclase o la super interfaz, devuelve verdadero, de lo contrario, falso.

Soleado
fuente