Un problema è che "ciò che JVM ha effettivamente fatto ad esso" modifiche tra invocazioni come la JVM è libero di ri-generare il codice.
Come esempio ho indagato alcuni giorni fa cosa fa Hotspot con i metodi final
rispetto ai metodi virtuali. A giudicare dalle microbenchmarks, le mie conclusioni sono state: JVM
Cliente: Se il metodo è efficace final
(non c'è alcun classe caricata che prevale su di esso), la JVM utilizza una chiamata non virtuale. Successivamente, se si carica una classe che sovrascrive questo metodo, la JVM modificherà il codice JIT per rendere virtuali le chiamate. Quindi dichiarare come final
non ha rilevanza significativa.
JVM server: Qui final
sembra non avere alcuna rilevanza. Ciò che sembra accadere è che JVM genera una chiamata non virtuale per qualsiasi classe che si sta utilizzando la prima volta, indipendentemente da qualsiasi classe venga caricata. Successivamente, se si effettua una chiamata da un oggetto di un'altra classe, la JVM applicherà una patch a tutte le chiamate con qualcosa di simile a questo (suppongo che profitterà anche le chiamate in modo che possa cambiare percorso veloce e percorso lento se non ottiene bene la prima volta):
if (object instanceof ClassOfNonVirtualCall) {
do non-virtual call to ClassOfNonVirtualCall.method
} else {
do virtual call to object.method
}
Se siete veramente interessati a vedere codice generato, si può giocare con DEBUG JVM da OpenJDK:
http://dlc.sun.com.edgesuite.net/jdk7/binaries/index.html
http://wikis.sun.com/display/HotSpotInternals/PrintAssembly
Infatti, il server VM incorpora un codice caso speciale per due classi: l'inlining bimorfo. Credo che questa funzione sia stata implementata per supportare i buffer di heap NIO diretti e Java. –