Iniziamo con due semplici classi:
package com.michaelt.so.supers;
public class Sup {
int methodA(int a, int b) {
return a + b;
}
}
e poi
package com.michaelt.so.supers;
public class Sub extends Sup {
@Override
int methodA(int a, int b) {
return super.methodA(a, b);
}
}
Compilando il metodoA e osservando il codice byte si ottiene:
methodA(II)I
L0
LINENUMBER 6 L0
ALOAD 0
ILOAD 1
ILOAD 2
INVOKESPECIAL com/michaelt/so/supers/Sup.methodA (II)I
IRETURN
L1
LOCALVARIABLE this Lcom/michaelt/so/supers/Sub; L0 L1 0
LOCALVARIABLE a I L0 L1 1
LOCALVARIABLE b I L0 L1 2
MAXSTACK = 3
MAXLOCALS = 3
E puoi vedere proprio lì con il metodo invokespecial che fa la ricerca contro il metodo della classe SupA ().
Il invokespecial opcode ha il seguente logica:
- Se C contiene una dichiarazione per un metodo di istanza con lo stesso nome e descrittore del metodo risolto, questo metodo verrà invocato. La procedura di ricerca termina.
- Altrimenti, se C ha una superclasse, questa stessa procedura di ricerca viene eseguita in modo ricorsivo usando la superclasse diretta di C. Il metodo da invocare è il risultato del richiamo ricorsivo di questa procedura di ricerca.
- In caso contrario, viene sollevato un AbstractMethodError.
In questo caso, non esiste un metodo di istanza con lo stesso nome e descrittore nella sua classe, quindi il primo punto non sparerà. Il secondo proiettile tuttavia - c'è una superclasse e invoca il metodo del superA.
Il compilatore non lo incorpora e non c'è una copia della fonte di Sup nella classe.
Tuttavia la storia non è ancora finita. Questo è solo il codice compilato . Una volta che il codice raggiunge la JVM, HotSpot può essere coinvolto.
Sfortunatamente, non ne so molto, quindi mi rivolgerò all'autorità in materia e andrò a Inlining in Java dove si dice che HotSpot può metodi in linea (anche metodi non definitivi).
Andando alla documentazione si osserva che se una particolare chiamata di metodo diventa un hot spot invece di fare quella ricerca ogni volta, questa informazione può essere inline - copiando in modo efficace il codice dal metodo SupA () nel metodo SubA ().
Questo è fatto in fase di runtime, in memoria, in base a come si comporta l'applicazione e quali sono le ottimizzazioni necessarie per velocizzare le prestazioni.
Come indicato in HotSpot Internals for OpenJDK "i metodi sono spesso in linea. Statico, privato, finale e / o le invocazioni "speciali" sono facili da allineare. "
Se apri le opzioni per la JVM trova un'opzione di -XX:MaxInlineSize=35
(35 è il valore predefinito) che è il numero massimo di byte che possono essere sottolineati. Sottolineerò che questo è il motivo per cui a Java piace avere molti piccoli metodi, perché possono essere facilmente integrati. Questi piccoli metodi diventano più veloci quando vengono chiamati più perché possono essere in linea. E mentre si può giocare con quel numero e renderlo più grande, le altre ottimizzazioni potrebbero risultare meno efficaci. (domanda SO correlata: Strategia di inlinea JIT HotSpot che indica una serie di altre opzioni per dare un'occhiata agli interni di inlining di quell'HotSpot sta facendo).
Quindi no - il codice non è in linea al momento della compilazione. E, sì, il codice potrebbe essere ben delineato in fase di esecuzione se le ottimizzazioni delle prestazioni lo richiedono.
E tutto ciò che ho scritto sull'integrazione di HotSpot si applica solo a HotSpot JVM distribuito da Oracle. Se guardi l'elenco di wikipedia delle macchine virtuali Java ci sono molti più di un semplice HotSpot e il modo in cui le JVM gestiscono l'inlining può essere completamente diverso da quello che ho descritto sopra. Apache Harmony, Dalvik, ART - le cose potrebbero funzionare diversamente là.