El impacto en el rendimiento del uso de instanceof en Java


Estoy trabajando en una aplicación y un enfoque de diseño implica un uso extremadamente pesado del operador instanceof. Aunque sé que el diseño OO generalmente intenta evitar usar instanceof, esa es una historia diferente y esta pregunta está puramente relacionada con el rendimiento. Me preguntaba si hay algún impacto en el rendimiento? Es tan rápido como ==?

Por ejemplo, tengo una clase base con 10 subclases. En una sola función que toma la clase base, compruebo si la clase es una instancia de la subclase y llevar a cabo alguna rutina.

Una de las otras formas en que pensé en resolverlo fue usar un entero primitivo "type id" en su lugar, y usar una máscara de bits para representar categorías de las subclases, y luego hacer una comparación de máscara de bits de las subclases "type id" a una máscara constante que representa la categoría.

Es instanceof de alguna manera optimizado por la JVM para ser más rápido que eso? Quiero meter a Java, pero el rendimiento de la aplicación es fundamental. Sería genial si alguien que ha sido por este camino antes podría ofrecer algunos consejos. ¿Soy demasiado quisquilloso o me estoy centrando en lo incorrecto para optimizar?

Author: JSK NS, 2008-09-19

23 answers

Los compiladores JVM/JIC modernos han eliminado el impacto en el rendimiento de la mayoría de las operaciones tradicionalmente "lentas", incluyendo instanceof, manejo de excepciones, reflexión, etc.

Como Donald Knuth escribió, "Debemos olvidarnos de las pequeñas eficiencias, digamos alrededor del 97% de las veces: la optimización prematura es la raíz de todo mal."El rendimiento de instanceof probablemente no será un problema, así que no pierdas el tiempo con soluciones alternativas exóticas hasta que estés seguro de que ese es el problema.

 237
Author: Steve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 16:45:45

Enfoque

Escribí un programa de referencia para evaluar diferentes implementaciones:

  1. instanceof aplicación (como referencia)
  2. objeto orientado a través de una clase abstracta y @Override un método de prueba
  3. usando una implementación de tipo propio
  4. getClass() == _.class aplicación

Usé jmh para ejecutar el benchmark con 100 llamadas de calentamiento, 1000 iteraciones bajo medición y con 10 bifurcaciones. Así que cada opción se midió con 10 000 tiempos, que toma 12: 18: 57 para ejecutar todo el benchmark en mi MacBook Pro con macOS 10.12.4 y Java 1.8. El índice de referencia mide el tiempo medio de cada opción. Para más detalles ver mi implementación en GitHub.

En aras de la integridad: Hay una versión anterior de esta respuesta y mi punto de referencia.

Resultados

| Operation  | Runtime in nanoseconds per operation | Relative to instanceof |
|------------|--------------------------------------|------------------------|
| INSTANCEOF | 39,598 ± 0,022 ns/op                 | 100,00 %               |
| GETCLASS   | 39,687 ± 0,021 ns/op                 | 100,22 %               |
| TYPE       | 46,295 ± 0,026 ns/op                 | 116,91 %               |
| OO         | 48,078 ± 0,026 ns/op                 | 121,42 %               |

Tl; dr

En Java 1.8 instanceof es el enfoque más rápido, aunque getClass() está muy cerca.

 216
Author: Michael Dorner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:26

Acabo de hacer una prueba simple para ver cómo instanceOf performance se compara con una simple llamada s. equals() a un objeto string con solo una letra.

En un bucle de 10.000.000 el instanceOf me dio 63-96ms, y el string equals me dio 106-230ms

Usé java jvm 6.

Así que en mi prueba simple es más rápido hacer una instanceOf en lugar de una comparación de una cadena de caracteres.

Usando Enteros .equals() en lugar de string me dio el mismo resultado, solo cuando usé el = = i fue más rápido que instanceOf por 20ms (en un bucle de 10.000.000)

 72
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-29 12:13:26

Los elementos que determinarán el impacto en el rendimiento son:

  1. El número de clases posibles para las que el operador instanceof podría devolver true
  2. La distribución de sus datos - ¿la mayoría de las instancias de operaciones se resuelven en el primer o segundo intento? Usted querrá poner sus operaciones más probables para devolver verdad primero.
  3. El entorno de implementación. La ejecución en una máquina virtual de Sun Solaris es significativamente diferente a la JVM de Windows de Sun. Solaris correrá en modo 'servidor' por defecto, mientras que Windows se ejecutará en modo cliente. Las optimizaciones JIT en Solaris, harán que todos los métodos de acceso puedan ser iguales.

He creado un microbenchmark para cuatro métodos diferentes de envío. Los resultados de Solaris son los siguientes, siendo el número más pequeño más rápido:

InstanceOf 3156
class== 2925 
OO 3083 
Id 3067 
 17
Author: brianegge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-02 03:35:56

Respondiendo a tu última pregunta: A menos que un perfilador te diga, que pasas cantidades ridículas de tiempo en una instancia de: Sí, eres quisquilloso.

Antes de pensar en optimizar algo que nunca necesitó ser optimizado: Escriba su algoritmo de la manera más legible y ejecútelo. Ejecútelo, hasta que el compilador jit tenga la oportunidad de optimizarlo por sí mismo. Si luego tiene problemas con esta pieza de código, use un generador de perfiles para indicarle dónde obtener el máximo beneficio y optimizar este.

En tiempos de compiladores altamente optimizados, es probable que sus conjeturas sobre los cuellos de botella sean completamente erróneas.

Y en el verdadero espíritu de esta respuesta (que creo sinceramente): Absolutamente no sé cómo instanceof y == se relacionan una vez que el compilador jit tuvo la oportunidad de optimizarlo.

Lo olvidé: Nunca midas la primera corrida.

 16
Author: Olaf Kock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-17 10:20:27

Tengo la misma pregunta, pero como no encontré 'métricas de rendimiento' para casos de uso similares a los míos, he hecho más código de muestra. En mi hardware y Java 6 & 7, la diferencia entre instanceof y switch en iteraciones de 10mln es

for 10 child classes - instanceof: 1200ms vs switch: 470ms
for 5 child classes  - instanceof:  375ms vs switch: 204ms

Por lo tanto, instanceof es realmente más lento, especialmente en un gran número de sentencias if-else-if, sin embargo, la diferencia será insignificante dentro de la aplicación real.

import java.util.Date;

public class InstanceOfVsEnum {

    public static int c1, c2, c3, c4, c5, c6, c7, c8, c9, cA;

    public static class Handler {
        public enum Type { Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, TypeA }
        protected Handler(Type type) { this.type = type; }
        public final Type type;

        public static void addHandlerInstanceOf(Handler h) {
            if( h instanceof H1) { c1++; }
            else if( h instanceof H2) { c2++; }
            else if( h instanceof H3) { c3++; }
            else if( h instanceof H4) { c4++; }
            else if( h instanceof H5) { c5++; }
            else if( h instanceof H6) { c6++; }
            else if( h instanceof H7) { c7++; }
            else if( h instanceof H8) { c8++; }
            else if( h instanceof H9) { c9++; }
            else if( h instanceof HA) { cA++; }
        }

        public static void addHandlerSwitch(Handler h) {
            switch( h.type ) {
                case Type1: c1++; break;
                case Type2: c2++; break;
                case Type3: c3++; break;
                case Type4: c4++; break;
                case Type5: c5++; break;
                case Type6: c6++; break;
                case Type7: c7++; break;
                case Type8: c8++; break;
                case Type9: c9++; break;
                case TypeA: cA++; break;
            }
        }
    }

    public static class H1 extends Handler { public H1() { super(Type.Type1); } }
    public static class H2 extends Handler { public H2() { super(Type.Type2); } }
    public static class H3 extends Handler { public H3() { super(Type.Type3); } }
    public static class H4 extends Handler { public H4() { super(Type.Type4); } }
    public static class H5 extends Handler { public H5() { super(Type.Type5); } }
    public static class H6 extends Handler { public H6() { super(Type.Type6); } }
    public static class H7 extends Handler { public H7() { super(Type.Type7); } }
    public static class H8 extends Handler { public H8() { super(Type.Type8); } }
    public static class H9 extends Handler { public H9() { super(Type.Type9); } }
    public static class HA extends Handler { public HA() { super(Type.TypeA); } }

    final static int cCycles = 10000000;

    public static void main(String[] args) {
        H1 h1 = new H1();
        H2 h2 = new H2();
        H3 h3 = new H3();
        H4 h4 = new H4();
        H5 h5 = new H5();
        H6 h6 = new H6();
        H7 h7 = new H7();
        H8 h8 = new H8();
        H9 h9 = new H9();
        HA hA = new HA();

        Date dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerInstanceOf(h1);
            Handler.addHandlerInstanceOf(h2);
            Handler.addHandlerInstanceOf(h3);
            Handler.addHandlerInstanceOf(h4);
            Handler.addHandlerInstanceOf(h5);
            Handler.addHandlerInstanceOf(h6);
            Handler.addHandlerInstanceOf(h7);
            Handler.addHandlerInstanceOf(h8);
            Handler.addHandlerInstanceOf(h9);
            Handler.addHandlerInstanceOf(hA);
        }
        System.out.println("Instance of - " + (new Date().getTime() - dtStart.getTime()));

        dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerSwitch(h1);
            Handler.addHandlerSwitch(h2);
            Handler.addHandlerSwitch(h3);
            Handler.addHandlerSwitch(h4);
            Handler.addHandlerSwitch(h5);
            Handler.addHandlerSwitch(h6);
            Handler.addHandlerSwitch(h7);
            Handler.addHandlerSwitch(h8);
            Handler.addHandlerSwitch(h9);
            Handler.addHandlerSwitch(hA);
        }
        System.out.println("Switch of - " + (new Date().getTime() - dtStart.getTime()));
    }
}
 12
Author: Xtra Coder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-23 19:06:10

instanceof es muy rápido, tomando solo unas pocas instrucciones de la CPU.

Aparentemente, si una clase X no tiene subclases cargadas (JVM lo sabe), instanceof se puede optimizar como:

     x instanceof X    
==>  x.getClass()==X.class  
==>  x.classID == constant_X_ID

El costo principal es solo una lectura!

Si X tiene subclases cargadas, se necesitan unas cuantas lecturas más; es probable que estén ubicadas conjuntamente, por lo que el costo adicional también es muy bajo.

¡Buenas noticias a todos!

 8
Author: irreputable,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 10:13:26

Instanceof probablemente va a ser más costoso que un simple igual en la mayoría de las implementaciones del mundo real (es decir, aquellas en las que instanceof es realmente necesario, y no se puede resolver simplemente anulando un método común, como todos los libros de texto para principiantes, así como Demian sugiere anteriormente).

¿Por qué es eso? Porque lo que probablemente va a suceder es que tienes varias interfaces, que proporcionan alguna funcionalidad (digamos, interfaces x, y y z), y algunos objetos para manipular que pueden (o no) implementar una de esas interfaces... pero no directamente. Digamos, por ejemplo, que tengo:

W extiende x

A implementa w

B extiende A

C extiende B, implementa y

D extiende C, implementa z

Supongamos que estoy procesando una instancia de D, el objeto d. Computing (d instanceof x) requiere tomar d. getClass (), recorrer las interfaces que implementa para saber si una es == a x, y si no hacerlo de nuevo recursivamente para todos sus antepasado... En nuestro caso, si haces una primera exploración de amplitud de ese árbol, produce al menos 8 comparaciones, suponiendo que y y z no extienden nada...

Es probable que la complejidad de un árbol de derivación del mundo real sea mayor. En algunos casos, el JIT puede optimizar la mayor parte de él lejos, si es capaz de resolver por adelantado d como siendo, en todos los casos posibles, una instancia de algo que se extiende x. Realista, sin embargo, usted va a ir a través de ese árbol atravesando la mayor parte de la tiempo.

Si eso se convierte en un problema, sugeriría usar un mapa de manejador en su lugar, vinculando la clase concreta del objeto a un cierre que realiza el manejo. Elimina la fase transversal del árbol en favor de una asignación directa. Sin embargo, tenga en cuenta que si ha establecido un controlador para C.class, mi objeto d anterior no será reconocido.

Aquí están mis 2 centavos, espero que ayuden...

 5
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-27 18:30:28

'instanceof' es en realidad un operador, como + o -, y creo que tiene su propia instrucción JVM bytecode. Debería ser bastante rápido.

No debería que si tiene un interruptor donde está probando si un objeto es una instancia de alguna subclase, entonces su diseño podría necesitar ser reelaborado. Considere empujar el comportamiento específico de la subclase hacia abajo en las propias subclases.

 4
Author: Outlaw Programmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 16:46:56

Instanceof es muy rápido. Se reduce a un bytecode que se utiliza para la comparación de referencia de clase. Pruebe algunos millones de instanceofs en un bucle y compruébelo usted mismo.

 4
Author: Apocalisp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 16:49:34

Instanceof es muy eficiente, por lo que es poco probable que su rendimiento sufra. Sin embargo, el uso de muchas instanceof sugiere un problema de diseño.

Si puedes usar xClass == String.clase, esto es más rápido. Nota: no necesitas instanceof para las clases finales.

 4
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-27 20:07:04

Es difícil decir cómo una determinada JVM implementa una instancia de, pero en la mayoría de los casos, los objetos son comparables a las estructuras y las clases también y cada estructura de objeto tiene un puntero a la estructura de clase de la que es una instancia. Así que realmente instanceof para

if (o instanceof java.lang.String)

Podría ser tan rápido como el siguiente código C

if (objectStruct->iAmInstanceOf == &java_lang_String_class)

Asumiendo que un compilador JIT está en su lugar y hace un trabajo decente.

Teniendo en cuenta que esto es solo acceder a un puntero, obtener un puntero en un cierto desplazamiento de la el puntero apunta y compara esto con otro puntero (que es básicamente lo mismo que probar números de 32 bits siendo iguales), diría que la operación puede ser realmente muy rápida.

No tiene por qué, sin embargo, depende mucho de la JVM. Sin embargo, si esto resultara ser la operación de cuello de botella en su código, consideraría la implementación de JVM bastante pobre. Incluso uno que no tiene compilador JIT y solo interpreta código debe ser capaz de hacer una prueba instanceof en prácticamente no tiempo.

 3
Author: Mecki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 16:58:13

InstanceOf es una advertencia de diseño pobre Orientado a Objetos.

Las JVM actuales significan que la instancia de no es una gran preocupación de rendimiento en sí misma. Si te encuentras usándolo mucho, especialmente para la funcionalidad principal, probablemente sea hora de mirar el diseño. Las ganancias de rendimiento (y simplicidad/mantenibilidad) de la refactorización a un mejor diseño superarán en gran medida cualquier ciclo de procesador real gastado en la llamada real instanceOf.

A dé un ejemplo de programación simplista muy pequeño.

if (SomeObject instanceOf Integer) {
  [do something]
}
if (SomeObject instanceOf Double) {
  [do something different]
}

Es una arquitectura pobre una mejor opción habría sido tener SomeObject como la clase padre de dos clases hijas donde cada clase hija anula un método (doSomething) para que el código se vea como tal:

Someobject.doSomething();
 3
Author: Demian Krige,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 17:15:09

Demian y Paul mencionan un buen punto; sin embargo , la colocación del código a ejecutar realmente depende de cómo se desea utilizar los datos...

Soy un gran fan de los objetos de datos pequeños que se pueden usar de muchas maneras. Si sigue el enfoque de anulación (polimórfica), sus objetos solo se pueden usar "de una manera".

Aquí es donde entran los patrones...

Puede usar doble envío (como en el patrón de visitante) para pedirle a cada objeto que" lo llame " pasando por sí mismo this esto lo hará resuelve el tipo del objeto. Sin embargo (de nuevo) necesitará una clase que pueda "hacer cosas" con todos los subtipos posibles.

Prefiero usar un patrón de estrategia, donde puede registrar estrategias para cada subtipo que desea manejar. Algo como lo siguiente. Tenga en cuenta que esto solo ayuda para las coincidencias de tipo exactas, pero tiene la ventaja de que es extensible: los colaboradores de terceros pueden agregar sus propios tipos y controladores. (Esto es bueno para marcos dinámicos como OSGi, donde nuevo se pueden agregar paquetes)

Esperemos que esto inspire algunas otras ideas...

package com.javadude.sample;

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

public class StrategyExample {
    static class SomeCommonSuperType {}
    static class SubType1 extends SomeCommonSuperType {}
    static class SubType2 extends SomeCommonSuperType {}
    static class SubType3 extends SomeCommonSuperType {}

    static interface Handler<T extends SomeCommonSuperType> {
        Object handle(T object);
    }

    static class HandlerMap {
        private Map<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>> handlers_ =
            new HashMap<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>>();
        public <T extends SomeCommonSuperType> void add(Class<T> c, Handler<T> handler) {
            handlers_.put(c, handler);
        }
        @SuppressWarnings("unchecked")
        public <T extends SomeCommonSuperType> Object handle(T o) {
            return ((Handler<T>) handlers_.get(o.getClass())).handle(o);
        }
    }

    public static void main(String[] args) {
        HandlerMap handlerMap = new HandlerMap();

        handlerMap.add(SubType1.class, new Handler<SubType1>() {
            @Override public Object handle(SubType1 object) {
                System.out.println("Handling SubType1");
                return null;
            } });
        handlerMap.add(SubType2.class, new Handler<SubType2>() {
            @Override public Object handle(SubType2 object) {
                System.out.println("Handling SubType2");
                return null;
            } });
        handlerMap.add(SubType3.class, new Handler<SubType3>() {
            @Override public Object handle(SubType3 object) {
                System.out.println("Handling SubType3");
                return null;
            } });

        SubType1 subType1 = new SubType1();
        handlerMap.handle(subType1);
        SubType2 subType2 = new SubType2();
        handlerMap.handle(subType2);
        SubType3 subType3 = new SubType3();
        handlerMap.handle(subType3);
    }
}
 3
Author: Scott Stanchfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-21 15:51:16

Generalmente la razón por la que el operador "instanceof" está mal visto en un caso como ese (donde la instanceof está verificando subclases de esta clase base) es porque lo que debería estar haciendo es mover las operaciones a un método y reemplazarlo para las subclases apropiadas. Por ejemplo, si usted tiene:

if (o instanceof Class1)
   doThis();
else if (o instanceof Class2)
   doThat();
//...

Puede reemplazar eso con

o.doEverything();

Y luego tener la implementación de" doEverything () "en Class1 llamar" DoThis ()", y en Class2 llamar " doThat ()", y así en.

 2
Author: Paul Tomblin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 16:46:05

En la versión moderna de Java, el operador instanceof es más rápido como una simple llamada a un método. Esto significa:

if(a instanceof AnyObject){
}

Es más rápido como:

if(a.getType() == XYZ){
}

Otra cosa es si necesita cascada muchos instanceof. Entonces un switch que solo llama una vez GetType () es más rápido.

 2
Author: Horcrux7,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 19:09:53

Si la velocidad es tu único objetivo, usar constantes int para identificar subclases parece reducir un milisegundo del tiempo

static final int ID_A = 0;
static final int ID_B = 1;
abstract class Base {
  final int id;
  Base(int i) { id = i; }
}
class A extends Base {
 A() { super(ID_A); }
}
class B extends Base {
 B() { super(ID_B); }
}
...
Base obj = ...
switch(obj.id) {
case  ID_A: .... break;
case  ID_B: .... break;
}

Terrible diseño de OO, pero si su análisis de rendimiento indica que aquí es donde está el cuello de botella, entonces tal vez. En mi código, el código de envío toma el 10% del tiempo total de ejecución y esto tal vez contribuyó a una mejora de la velocidad total del 1%.

 1
Author: Salix alba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-27 14:13:43

Me pondré en contacto con usted en instanceof performance. Pero una manera de evitar problemas (o la falta de ellos) por completo sería crear una interfaz padre para todas las subclases en las que necesita hacer instanceof. La interfaz será un súper conjunto de todos los métodos en subclases para los que necesita hacer instanceof check. Cuando un método no se aplique a una subclase específica, simplemente proporcione una implementación ficticia de este método. Si no malinterpreté el tema, así es como he llegado alrededor del problema en el pasado.

 1
Author: Jose Quijada,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-15 22:53:22

Debes medir/perfilar si realmente es un problema de rendimiento en tu proyecto. Si lo es, recomendaría un rediseño, si es posible. Estoy bastante seguro de que no puedes superar la implementación nativa de la plataforma (escrita en C). También debe considerar la herencia múltiple en este caso.

Debería contar más sobre el problema, tal vez podría usar un almacén asociativo, por ejemplo, un Map si solo está interesado en los tipos concretos.

 0
Author: Karl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 16:50:42

Con respecto a la nota de Peter Lawrey de que no necesita instanceof para las clases finales y solo puede usar una igualdad de referencia, ¡tenga cuidado! Aunque las clases finales no se pueden extender, no se garantiza que sean cargadas por el mismo classloader. Solo use x. getClass () = = SomeFinal.class o su clase si estás absolutamente seguro de que solo hay un classloader en juego para esa sección del código.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 01:25:01

También prefiero un enfoque enum, pero usaría una clase base abstracta para forzar a las subclases a implementar el método getType().

public abstract class Base
{
  protected enum TYPE
  {
    DERIVED_A, DERIVED_B
  }

  public abstract TYPE getType();

  class DerivedA extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_A;
    }
  }

  class DerivedB extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_B;
    }
  }
}
 0
Author: mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-13 15:38:05

Pensé que podría valer la pena presentar un contra-ejemplo al consenso general en esta página de que "instanceof" no es lo suficientemente caro como para preocuparse. Encontré que tenía algún código en un bucle interno que (en algún intento histórico de optimización) hizo

if (!(seq instanceof SingleItem)) {
  seq = seq.head();
}

Donde llamar a head() en un SingleItem devuelve el valor sin cambios. Sustitución del código por

seq = seq.head();

Me da una velocidad de 269ms a 169ms, a pesar del hecho de que hay algunas cosas bastante pesadas sucediendo en el bucle, como la conversión de cadena a doble. Es posible, por supuesto, que la aceleración se deba más a la eliminación de la rama condicional que a la eliminación de la instancia del operador en sí; pero pensé que vale la pena mencionarlo.

 0
Author: Michael Kay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-16 07:53:53

Te estás centrando en lo equivocado. La diferencia entre instanceof y cualquier otro método para comprobar lo mismo probablemente ni siquiera sería mensurable. Si el rendimiento es crítico, entonces Java es probablemente el lenguaje equivocado. La razón principal es que no se puede controlar cuando la máquina virtual decide que quiere ir a recoger basura, lo que puede llevar a la CPU al 100% durante varios segundos en un programa grande (MagicDraw 10 fue genial para eso). A menos que usted está en control de cada ordenador este programa no puede garantizar en qué versión de JVM estará, y muchos de los más antiguos tenían problemas de velocidad importantes. Si se trata de una aplicación pequeña que puede estar bien con Java, pero si usted está constantemente leyendo y descartando datos entonces se dará cuenta cuando el GC entra en acción.

 -3
Author: tloach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 16:51:11