2010-04-30 11 views
6

Pregunta simple, pero respuesta difícil, supongo.Java rendimiento de la interfaz genérica

¿El uso de interfaces genéricas perjudica el rendimiento?

Ejemplo:

public interface Stuff<T> { 

    void hello(T var); 
} 

vs 

public interface Stuff { 

    void hello(Integer var); <---- Integer used just as an example 
} 

Lo primero que pensé es que no lo hace. Los genéricos son solo parte del lenguaje y el compilador lo optimizará como si no hubiera genéricos (al menos en este caso particular de interfaces genéricas).

¿Es esto correcto?

+1

No son directamente comparables, por lo que puedo ver. ¿No debería el segundo ejemplo tomar 'Object' como parámetro? –

Respuesta

10

Existe la posibilidad de una pérdida de rendimiento menor, porque el compilador algunas veces agrega métodos de puente sintético. Consideremos el siguiente ejemplo:

public class GenericPerformance { 
    public static void main(final String[] args) { 
     final Stuff<Integer> stuff = new IntStuff(); 
     final Integer data = stuff.getData(); 
     stuff.putData(data); 
    } 
} 

interface Stuff<T> { 
    T getData(); 
    void putData(T stuff); 
} 

class IntStuff implements Stuff<Integer> { 
    private Integer stuff; 
    public Integer getData() { 
     return stuff; 
    } 
    public void putData(final Integer stuff) { 
     this.stuff = stuff; 
    } 
} 

Si nos fijamos en el código de bytes generada, verá: en el método principal, los métodos de interfaz borrados

java.lang.Object Stuff.getData() 
void Stuff.putData(java.lang.Object) 

se invocan. Que los métodos, implementados en IntStuff con las firmas

java.lang.Object getData() 
void putData(java.lang.Object) 

tanto con los modificadores public bridge synthetic, delegado a los métodos "reales"

java.lang.Integer IntStuff.getData() 
void putData(java.lang.Integer) 

El primer método sintético simplemente devuelve el resultado Integer, mientras que la segunda realiza un lanzamiento de Object a Integer antes de llamar al putData(Integer).

Si cambia la variable stuff al tipo IntStuff, se invocan ambos métodos Integer en lugar de los métodos sintéticos Object.

+1

+1, me gusta, los métodos sintéticos añaden gastos generales, aunque se trata de una micro-optimización que el JIT probablemente optimizará de todos modos, por lo que a nadie le debería importar a menos que se presente un problema. Pero es útil saberlo en el caso. – Yishai

+2

Tienes razón. Por lo general, la sobrecarga * no * vale la pena el esfuerzo de evitar los genéricos. Pero parece que el JIT no puede optimizar completamente el método del puente. Acabo de realizar algunas pruebas con un ciclo que contiene solo 'Integer final data = intstuff.getData(); intstuff.putData (datos); '. Ejecutar el ciclo con una variable 'Stuff stuff' necesita un 30% más de tiempo que con una variable' IntStuff stuff', incluso con la opción '-server' JVM. –

7

Yup - java generics es una construcción completamente en tiempo de compilación. La JVM lo ve como una interfaz normal. Por lo tanto, no hay ganancia o pérdida de rendimiento en el tiempo de ejecución con genéricos.

4

Son simplemente un ayudante en tiempo de compilación para obtener seguridad tipo.

Los genéricos se implementan por borrado de tipo: la información de tipo genérico está presente solo en tiempo de compilación, después de lo cual es borrado por el compilador.

Tomado de: http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html

1

En realidad, creo que en su ejemplo no ES una pequeña diferencia de rendimiento. La forma compilada de la primera versión supone que hello() recibe un Objeto, mientras que en el segundo asume un Entero. Por lo tanto, al instanciar StuffImpl < Entero>, las llamadas a hello() serán un poco más lentas debido al reparto implícito agregado por el compilador.

- CORRECCION -

La conversión implícita no se añadirá a hello(). Sin embargo, si agrega un método getter que devuelve T, el molde se agregará al valor devuelto.

La conclusión es que el uso de genéricos introduce un impacto negativo en el rendimiento en algunos casos, en comparación con el código no genérico restringido a tipos específicos.

+0

Para cualquier implementación concreta de 'Stuff ', p. con T como 'Integer', habrá un molde implícito de' Object' al tipo concreto, 'Integer'. Ver mi respuesta para más detalles. –

Cuestiones relacionadas