2010-06-12 10 views
23

¿Hay alguna diferencia en la eficiencia (por ejemplo, el tiempo de ejecución, el tamaño del código, etc.) entre estas dos formas de hacer las cosas?Implicaciones de la eficiencia de la clase anónima de Java

A continuación se encuentran ejemplos diseñados que crean objetos y no hacen nada, pero mis escenarios reales pueden estar creando nuevos hilos, oyentes, etc. Suponga que las siguientes piezas de código ocurren en un bucle para que pueda marcar la diferencia.

Uso de objetos anónimos:

void doSomething() { 
    for (/* Assume some loop */) { 
     final Object obj1, obj2; // some free variables 

     IWorker anonymousWorker = new IWorker() { 
      doWork() { 
       // do things that refer to obj1 and obj2 
      } 
     }; 
    } 
} 

Definición de una clase primera:

void doSomething() { 
    for (/* Assume some loop */) { 
     Object obj1, obj2; 
     IWorker worker = new Worker(obj1, obj2); 
    } 
} 

static class Worker implements IWorker { 
    private Object obj1, obj2; 
    public CustomObject(Object obj1, Object obj2) {/* blah blah */} 

    @Override 
    public void doWork() {} 
}; 
+3

Debe hacer lo que cree que es el más claro y fácil de entender, la diferencia de rendimiento debe ser mucho menor que el trabajo que realiza en doWork() por lo que no hará la diferencia. Si tuviera que estimar la diferencia, esperaría unos 10 nano segundos. –

+0

A menos que estuviese haciendo un código de rendimiento crítico y su conferencia no sea – LegendLength

Respuesta

37

la única diferencia práctica entre las clases anónimas y las clases de nivel superior es que las clases anónimas sostendrán una referencia implícita a la clase externa.

Esto no se manifestará en el rendimiento, pero le afectará si alguna vez serializa estas clases.

+9

Impactará el rendimiento si no tiene sentido que las referencias a la clase externa se mantengan con vida, especialmente cuando el camión de la basura rueda. Recolectará más basura a la vez en lugar de dejar que la clase externa se salga del alcance según sea necesario. No es una gran diferencia, pero no debe pasarse por alto. – dcow

+1

@dcow se preocupe por explicar, no entendí exactamente su deriva cuando dijo '... que las referencias a la clase externa se mantengan vivas' ¿Quiso decir si la clase interna guarda referencias a la clase externa? – Cu7l4ss

+3

@ Cu7l4ss - las clases internas * do * tienen una referencia a la clase externa. Normalmente no es visible pero está allí –

16

Debería haber poca o ninguna diferencia de rendimiento. Si hay una diferencia, estará en un nivel en el que no vale la pena preocuparse.

OMI, usted debe centrarse en la escritura de código que sea legible y fácil de mantener, e ignorar los problemas de rendimiento "micro" hasta que tenga claro evidencia de que son significativos ... basado en el perfil de la aplicación.

(Para el registro, cuando una clase interna anónima se refiere a un final en un ámbito circundante, esto se implementa en el nivel de código de bytes por medio de argumentos de constructor ocultos y instancia oculta atributos. Los bytecodes serán casi el mismo que el códigos de bytes que se obtienen de la otra aplicación.)

16

Es importante darse cuenta de que las clases anónimas siguen siendo clases conocidas y compiladas por completo en tiempo de compilación. El hecho de que, por ejemplo, esté definiendo un cuerpo de clase anónimo, quizás con muchos métodos y campos, etc. dentro de un bucle, no significa que el tiempo de ejecución tenga que compilar ese tipo en cada iteración.

Por lo tanto, cualquier diferencia en el rendimiento entre los dos enfoques es insignificante. Los factores importantes a considerar son cosas como la legibilidad, la reutilización, la capacidad de prueba, etc.

1

Especular sobre el rendimiento del código es una excelente manera de perder su tiempo. Nada se compara con comparar realmente el código. Si le preocupa el rendimiento, mida el código. Si sospecha que su código no es óptimo, perfile el código para averiguar dónde se gasta el tiempo, luego intente mejorar esas partes. En este momento, puede ser apropiado estudiar realmente el código de bytes para ver si eso puede darle una pista sobre qué implementación es más eficiente.

Cuando haya hecho eso, mida nuevamente el código para asegurarse de que no empeorará las cosas, por ejemplo, haciendo el código más feo y más difícil de mantener.

3

De hecho, he notado un impacto significativo en el rendimiento al crear instancias de muchas instancias de una clase anónima.

Pensando si podría deberse a que la clase local es estática lo eliminé y no hizo ninguna diferencia.

En mi caso, estaba haciendo algo 1000 elijo 3 veces, que es 499,500. La versión con la clase local (independientemente de la estática o no) tomó 26 segundos y la versión con la clase anónima funcionalmente idéntica tomó 2 minutos y 20 segundos.

+0

Hay muchas cosas a considerar ya que las clases anidadas también pueden causar efectos secundarios adicionales si se usan en exceso. Por ejemplo, cualquier intento de acceder a miembros o métodos privados de otro objeto (como el externo) terminará en un método público (un getter simple) que se generará y usará en su lugar. Eso es algo que debes tener en cuenta al anidar la lógica. No tiene el enlace para esto, pero lo encontró hace algún tiempo en la especificación de JVM. – Pijusn

+0

Sería útil si proporcionó su código de referencia para respaldar esto. –

3

En cuanto al rendimiento, debe considerar si se debe crear o no una clase interna.

Un ejemplo de mala práctica es algo así como:

public List<String> someMethod() { 
     return new ArrayList<String>() {{ 
         add("Item one"); 
         add("Item two"); 
       }}; 
} 

Si bien esta comodidad sintáctica parece inteligente, a primera vista, este (a menudo sin darse cuenta) crea una clase interna anónima cuyo objeto mantiene una referencia a la instancia externa . Como este objeto también se da al exterior como el valor de resultado de someMethod, no puede estar seguro de lo que su interlocutor hace con esta lista. Si pone la instancia ArrayList resultante en alguna variable estática, su Objeto actual también se mantendrá para siempre.

+0

Entonces, ¿cómo devuelves la lista? ¿Cuál es su propuesta para una mejor práctica? Gracias – jlanza

+0

¿Pidiendo un comentario de tres años? Ok, bueno, desde Java 7 eso sería devolver Arrays.asList ("Item one", "Item two"); ¿No es así? – Det

Cuestiones relacionadas