2010-04-30 18 views
6

Domanda semplice, ma difficile risposta, credo.Prestazioni di interfaccia generica Java

L'utilizzo di interfacce generiche fa male alle prestazioni?

Esempio:

public interface Stuff<T> { 

    void hello(T var); 
} 

vs 

public interface Stuff { 

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

Il mio primo pensiero è che non è così. I generici sono solo una parte del linguaggio e il compilatore lo ottimizzerà come se non ci fossero generici (almeno in questo caso particolare di interfacce generiche).

È corretto?

+1

Non sono direttamente confrontabili, per quanto posso vedere. Non dovrebbe il secondo esempio prendere 'Object' come parametro? –

risposta

10

C'è un potenziale per una minore perdita di prestazioni, perché il compilatore a volte aggiunge metodi di bridge sintetici. Si consideri il seguente esempio:

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; 
    } 
} 

Se si guarda il bytecode generato, si vedrà: Nel metodo Main, i metodi di interfaccia cancellati

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

vengono invocati. Che i metodi, implementati in IntStuff con le firme

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

sia con i modificatori public bridge synthetic, delegano ai metodi "reale"

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

Il primo metodo sintetico semplicemente restituisce il risultato intero, mentre il secondo esegue un cast da Object a Integer prima di chiamare putData(Integer).

Se si modifica la variabile stuff per digitare IntStuff, vengono chiamati entrambi i metodi Integer anziché i metodi sintetici Object.

+1

+1, bastonatemi, i metodi sintetici aggiungono overhead - anche se si tratta di una micro-ottimizzazione che il JIT probabilmente ottimizzerà comunque, quindi nessuno dovrebbe preoccuparsene a meno che un problema non si presenti realmente. Ma è utile sapere nel caso. – Yishai

+2

Hai ragione. Di solito, il sovraccarico non * vale * lo sforzo di evitare i generici. Ma sembra che il JIT non possa ottimizzare completamente il metodo bridge. Ho appena eseguito alcuni test con un ciclo contenente solo dati interi finali = intstuff.getData(); intstuff.putData (dati); '. L'esecuzione del ciclo con una variabile 'stuff richiede il 30% di tempo in più rispetto a una variabile' IntStuff stuff', anche con l'opzione JVM '-server'. –

7

Yup - java generics è un costrutto interamente in fase di compilazione. La JVM la vede come una normale interfaccia. Quindi non ci sono guadagni o perdite di prestazioni in runtime con i generici.

4

Sono semplicemente un aiutante in fase di compilazione per ottenere la sicurezza del tipo.

I generici vengono implementati mediante cancellazione di tipi: le informazioni di tipo generico sono presenti solo al momento della compilazione, dopodiché vengono cancellate dal compilatore.

Tratto da: http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html

1

In realtà, credo che nel tuo esempio ci IS una piccola differenza di prestazioni. Il modulo compilato della prima versione presuppone che hello() riceva un oggetto, mentre nel secondo assume un numero intero. Pertanto, quando instanziate StuffImpl < Integer>, le chiamate a hello() saranno un po 'più lente a causa del cast implicito aggiunto dal compilatore.

- CORREZIONE -

Il cast implicito non saranno aggiunti al ciao(). Tuttavia, se si aggiunge un metodo getter che restituisce T, il cast verrà aggiunto al valore restituito.

La linea di fondo è - l'utilizzo di generici introduce un impatto negativo sulle prestazioni in alcuni casi, rispetto al codice non generico limitato a tipi specifici.

+0

Per qualsiasi implementazione concreta di 'Stuff ', ad es. con T come 'Integer', ci sarà un cast implicito da' Object' al tipo concreto, 'Integer'. Vedi la mia risposta per i dettagli. –

Problemi correlati