instancia de Vs getClass ()

114

Veo ganancia en el rendimiento al utilizar getClass()y ==operador de más de instanceOfoperador.

Object  str = new Integer("2000");

long starttime = System.nanoTime();

if(str instanceof String) {
    System.out.println("its string");
} else {
    if (str instanceof Integer) {
        System.out.println("its integer");

    }
}

System.out.println((System.nanoTime()-starttime));

starttime = System.nanoTime();

if(str.getClass() == String.class) {
    System.out.println("its string in equals");
} else {
    if(str.getClass() == Integer.class) {
        System.out.println("its integer");
    }
}

System.out.println((System.nanoTime()-starttime));

¿Hay alguna pauta, cuál usar getClass()o instanceOf?

Dado un escenario: sé las clases exactas que se deben emparejar, es decir String, Integer(estas son clases finales), etc.

¿Es una instanceOfmala práctica utilizar el operador?

gota
fuente
3
Esto se explica en: stackoverflow.com/questions/596462/… .
Clement P
2
Su método de cronometraje está provocando retrasos artificiales y produciendo resultados de cronometraje incorrectos. Cambie el orden en el que realiza las comprobaciones y verá que la primera comprobación que haga (ya sea == o instanceof) siempre será más larga. Supongo que es el println () s. Nunca debes incluir esas cosas en tu bloque de tiempo.
kurtzmarc
Aparte de un comentario, para comparar el rendimiento, utilice iteraciones de ciclos múltiples (por ejemplo, 10000) para mejorar la precisión. Una sola invocación no es una buena medida.
martins.tuga

Respuestas:

140

La razón por la que el desempeño de instanceofy getClass() == ...es diferente es que están haciendo cosas diferentes.

  • instanceofcomprueba si la referencia de objeto en el lado izquierdo (LHS) es una instancia del tipo en el lado derecho (RHS) o algún subtipo .

  • getClass() == ... comprueba si los tipos son idénticos.

Entonces, la recomendación es ignorar el problema de rendimiento y usar la alternativa que le brinde la respuesta que necesita.

¿Es una instanceOfmala práctica utilizar el operador?

No necesariamente. El uso excesivo de cualquiera instanceOfo getClass() puede ser "olor a diseño". Si no tiene cuidado, terminará con un diseño en el que la adición de nuevas subclases da como resultado una cantidad significativa de reelaboración de código. En la mayoría de situaciones, el enfoque preferido es utilizar polimorfismo.

Sin embargo, hay casos en los que NO son "olor de diseño". Por ejemplo, equals(Object)debe probar el tipo real del argumento y devolverlo falsesi no coincide. Esto se hace mejor usando getClass().


Términos como "mejores prácticas", "malas prácticas", "olor de diseño", "antipatrón", etc. deben usarse con moderación y tratarse con sospecha. Fomentan el pensamiento en blanco o negro. Es mejor hacer sus juicios en contexto, en lugar de basarse puramente en dogmas; por ejemplo, algo que alguien dijo es "la mejor práctica".

Stephen C
fuente
@StephenC Como dijiste, es code smellpara usar. Eso significa que es una consecuencia de un código de mal diseño (no polimórfico) que hace que lo uses. ¿Puedo inferir el uso de cualquiera de ellos de esta manera?
sobreintercambio
@overexchange - 1) Dije "uso excesivo", no "uso". 2) Aparte de eso, no entiendo lo que estás preguntando. ¿Qué quieres decir con "inferir el uso ..." ??? El código usa estas cosas o no las usa.
Stephen C
Deduzco que el uso de instanceof& getClass()entra en escena debido a un mal diseño (no polimórfico) de código existente. ¿Estoy en lo correcto?
sobreintercambio
5
@overexchange: no puede inferir válidamente que todo uso de instanceof(por ejemplo) sea un mal diseño. Hay situaciones en las que puede ser la mejor solución. Lo mismo para getClass(). Repetiré que dije "uso excesivo" y no "uso" . Cada caso necesita ser juzgado por sus méritos ... no aplicando ciegamente alguna regla dogmática mal fundada.
Stephen C
44

¿Desea hacer coincidir una clase exactamente , por ejemplo, solo coincidir en FileInputStreamlugar de cualquier subclase de FileInputStream? Si es así, use getClass()y ==. Normalmente haría esto en un equals, para que una instancia de X no se considere igual a una instancia de una subclase de X; de lo contrario, puede tener problemas de simetría complicados. Por otro lado, suele ser más útil para comparar que dos objetos son de la misma clase que de una clase específica.

De lo contrario, utilice instanceof. Tenga en cuenta que con getClass()tendrá que asegurarse de tener una referencia no nula para comenzar, o obtendrá un NullPointerException, mientras instanceofque simplemente regresará falsesi el primer operando es nulo.

Personalmente, diría que instanceofes más idiomático, pero usar cualquiera de ellos de manera extensiva es un olor a diseño en la mayoría de los casos.

Jon Skeet
fuente
18

Sé que ha pasado un tiempo desde que se preguntó esto, pero ayer aprendí una alternativa.

Todos sabemos que puedes hacer:

if(o instanceof String) {   // etc

pero ¿y si no sabes exactamente qué tipo de clase debe ser? genéricamente no puedes hacer:

if(o instanceof <Class variable>.getClass()) {   

ya que da un error de compilación.
En cambio, aquí hay una alternativa: isAssignableFrom ()

Por ejemplo:

public static boolean isASubClass(Class classTypeWeWant, Object objectWeHave) {

    return classTypeWeWant.isAssignableFrom(objectWeHave.getClass())
}
Andy Dingfelder
fuente
8
No lo use isAssignableFrom. La forma correcta de escribir o instanceof Stringutilizando la reflexión es String.getClass().isInstance(o). El javadoc incluso lo dice: este método es el equivalente dinámico del instanceofoperador del lenguaje Java .
Andreas
3

getClass () tiene la restricción de que los objetos solo son iguales a otros objetos de la misma clase, el mismo tipo de tiempo de ejecución, como se ilustra en la salida del siguiente código:

class ParentClass{
}
public class SubClass extends ParentClass{
    public static void main(String []args){
        ParentClass parentClassInstance = new ParentClass();
        SubClass subClassInstance = new SubClass();
        if(subClassInstance instanceof ParentClass){
            System.out.println("SubClass extends ParentClass. subClassInstance is instanceof ParentClass");
        }
        if(subClassInstance.getClass() != parentClassInstance.getClass()){
            System.out.println("Different getClass() return results with subClassInstance and parentClassInstance ");
        }
    }
}

Salidas:

SubClass extiende ParentClass. subClassInstance es una instancia de ParentClass.

Diferentes getClass () devuelven resultados con subClassInstance y parentClassInstance.

Saurav Sahu
fuente