¿Cuál de los siguientes es mejor?
a instanceof B
o
B.class.isAssignableFrom(a.getClass())
La única diferencia que sé es que, cuando 'a' es nulo, el primero devuelve falso, mientras que el segundo arroja una excepción. Aparte de eso, ¿siempre dan el mismo resultado?
java
instanceof
reflection
Megamug
fuente
fuente
Respuestas:
Cuando se utiliza
instanceof
, debe conocer la clase deB
en tiempo de compilación. Cuando se usaisAssignableFrom()
puede ser dinámico y cambiar durante el tiempo de ejecución.fuente
a instanceof Bref.getClass()
. ¿Cómo puede ser esta la respuesta aceptada con tan poca explicación (o su falta de ella)?a instanceof Bref
no esa instanceof Bref.class
. El segundo argumento para el operador instanceof es un nombre de clase, no una expresión que se resuelve en una instancia de objeto de clase.B.class.isAssignableFrom(a.getClass())
, B es conocido ya instanceof B
es mejor. ¿Derecha?instanceof
solo se puede usar con tipos de referencia, no con tipos primitivos.isAssignableFrom()
se puede usar con cualquier objeto de clase:Ver http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class) .
fuente
Hablando en términos de rendimiento:
TL; DR
Utilice isInstance o instanceof que tienen un rendimiento similar. isAssignableFrom es un poco más lento.
Ordenado por rendimiento:
Basado en un punto de referencia de 2000 iteraciones en JAVA 8 Windows x64, con 20 iteraciones de calentamiento.
En teoria
Usando un visor de código de bytes suave , podemos traducir cada operador en código de bytes.
En el contexto de:
JAVA:
Bytecode:
JAVA:
Bytecode:
JAVA:
Bytecode:
Al medir cuántas instrucciones de bytecode utiliza cada operador, podríamos esperar que instancia de e isInstance sea más rápido que isAssignableFrom . Sin embargo, el rendimiento real NO está determinado por el código de bytes sino por el código de la máquina (que depende de la plataforma). Hagamos un micro benchmark para cada uno de los operadores.
El punto de referencia
Crédito: Según lo aconsejado por @ aleksandr-dubinsky, y gracias a @yura por proporcionar el código base, aquí hay un punto de referencia de JMH (consulte esta guía de ajuste ):
Obtuve los siguientes resultados (el puntaje es una cantidad de operaciones en una unidad de tiempo , por lo tanto, cuanto mayor sea el puntaje, mejor):
Advertencia
instanceof
en el contexto de su código podría optimizarse más fácilmente que,isInstance
por ejemplo, ...Para darle un ejemplo, tome el siguiente ciclo:
Gracias al JIT, el código se optimiza en algún momento y obtenemos:
Nota
Originalmente, esta publicación estaba haciendo su propio punto de referencia utilizando un bucle for en Java sin procesar, que dio resultados poco confiables ya que algunas optimizaciones como Just In Time pueden eliminar el bucle. Por lo tanto, medía principalmente cuánto tiempo tardó el compilador JIT en optimizar el ciclo: consulte Prueba de rendimiento independiente del número de iteraciones para obtener más detalles
Preguntas relacionadas
fuente
instanceof
es un código de bytes que utiliza esencialmente la misma lógica quecheckcast
(el código de bytes detrás de la transmisión). Inherentemente será más rápido que las otras opciones, independientemente del grado de optimización de JITC.isAssignableFrom()
es dinámico.Un equivalente más directo a
a instanceof B
esEsto funciona (devuelve falso) cuando
a
esnull
demasiado.fuente
Además de las diferencias básicas mencionadas anteriormente, existe una diferencia sutil central entre la instancia del operador y el método AsignableFrom en la clase.
Lea
instanceof
como “es esta (la parte izquierda) la instancia de esta o cualquier subclase de esto (la parte derecha)” y leax.getClass().isAssignableFrom(Y.class)
como “¿Puedo escribir?X x = new Y()
". En otras palabras, el operador instanceof verifica si el objeto izquierdo es el mismo o la subclase de la clase derecha, mientras queisAssignableFrom
verifica si podemos asignar el objeto de la clase de parámetro (from) a la referencia de la clase en la que se llama el método.Tenga en cuenta que ambos consideran la instancia real, no el tipo de referencia.
Considere un ejemplo de 3 clases A, B y C donde C se extiende B y B se extiende A.
fuente
b instanceof A
es equivalente aA.class.isAssignableFrom(b.getClass())
(como notó el OP). Su ejemplo es correcto pero irrelevante.new Y()
puede no ser legal siY
es abstracto o sin constructor público predeterminado, puede decir queX x = (Y)null
es legal si y solo six.getClass().isAssignableFrom(Y.class)
es verdadero.También hay otra diferencia:
instancia nula de X es
false
no importa lo que sea Xnull.getClass (). isAssignableFrom (X) arrojará una NullPointerException
fuente
null instanceof X
(donde X es una clase conocida en tiempo de compilación) siempre volveráfalse
.X.class.isAssignableFrom(null.getClass())
¿no? Pero sí, solicitargetClass()
una referencia nula dará como resultado NPE.getClass()
, no se debe usarisAssignableFrom
en primer lugar: la operación está destinada a la situación de no tener objetos. Si usted tiene la referencia de objetoa
, el usoa instanceof SomeClass
(si lo hace saber el tipoSomeClass
) osomeObject.getClass().isInstance(a)
(si no conoce el tipo desomeObject
).Hay otra diferencia más. Si el tipo (Clase) para probar es dinámico, por ejemplo, se pasa como un parámetro de método, entonces instanceof no lo cortará por usted.
pero puedes hacer:
Vaya, veo que esta respuesta ya está cubierta. Quizás este ejemplo sea útil para alguien.
fuente
this
),clazz.isInstance(this)
sería mejor en su ejemplo.Este hilo me dio una idea de cómo
instanceof
diferíaisAssignableFrom
, así que pensé en compartir algo propio.He encontrado que usando
isAssignableFrom
es la única forma (probablemente no la única, pero posiblemente la más fácil) de preguntarse si una referencia de una clase puede tomar instancias de otra, cuando uno tiene instancias de ninguna clase para hacer la comparación.Por lo tanto, no encontré que usar el
instanceof
operador para comparar la asignabilidad fuera una buena idea cuando todo lo que tenía eran clases, a menos que contemplara crear una instancia de una de las clases; Pensé que esto sería descuidado.fuente
instanceof tampoco se puede usar con tipos primitivos o genéricos. Como en el siguiente código:
El error es: No se puede realizar una instancia de comprobación con el parámetro de tipo T. Utilice en su lugar el objeto de borrado, ya que se borrará más información de tipo genérico en tiempo de ejecución.
No se compila debido a que la eliminación de tipo elimina la referencia de tiempo de ejecución. Sin embargo, el siguiente código compilará:
fuente
Considere la siguiente situación. Supongamos que desea verificar si el tipo A es una superclase del tipo de obj, puede ir
... A.class.isAssignableFrom (obj.getClass ()) ...
O
... obj instancia de A ...
Pero la solución isAssignableFrom requiere que el tipo de obj sea visible aquí. Si este no es el caso (p. Ej., El tipo de obj podría ser de una clase interna privada), esta opción está desactivada. Sin embargo, la instancia de solución siempre funcionaría.
fuente
obj
en este ejemplo) de cualquier tipo , puede llamar algetClass()
método público para obtener los metadatos de reflexión para la clase implementadora. Esto es cierto incluso si ese tipo de clase de implementación no sería legalmente visible en esa ubicación en el momento de la compilación. OK Es en tiempo de ejecución, ya que, para que usted mantenga laobj
referencia, alguna ruta de código que finalmente hizo tener acceso legal a la clase creó uno y dio (filtrado?) A usted.El pseudocódigo anterior es una definición de, si las referencias de tipo / clase A son asignables a partir de referencias de tipo / clase B. Es una definición recursiva. Para algunos puede ser útil, para otros puede ser confuso. Lo agrego en caso de que alguien lo encuentre útil. Esto es solo un intento de capturar mi comprensión, no es la definición oficial. Se utiliza en una determinada implementación de Java VM y funciona para muchos programas de ejemplo, por lo que, aunque no puedo garantizar que capture todos los aspectos de isAssignableFrom, no está completamente desactivado.
fuente
Hablando en términos de rendimiento "2" (con JMH):
Da:
Para que podamos concluir: instancia de tan rápido como isInstance () y isAssignableFrom () no muy lejos (+ 0.9% en tiempo de ejecución). Así que no hay diferencia real sea lo que sea que elijas
fuente
¿Qué tal algunos ejemplos para mostrarlo en acción ...
fuente
Algunas pruebas que hicimos en nuestro equipo muestran que
A.class.isAssignableFrom(B.getClass())
funciona más rápido queB instanceof A
. Esto puede ser muy útil si necesita verificar esto en una gran cantidad de elementos.fuente
instanceof
, creo que usted tiene serios problemas de diseño ...