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);
}
}
Metodo di compilazione A e guardando 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 la classe Sup methodA ().
Il codice operativo invokespecial ha la seguente logica:
- Se C contiene una dichiarazione per un metodo di istanza con lo stesso nome e lo stesso 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 utilizzando la superclasse diretta di C. Il metodo da invocare è il risultato dell'invocazione ricorsiva di questa procedura di ricerca.
- Altrimenti, viene generato un AbstractMethodError.
In questo caso, non esiste un metodo di istanza con lo stesso nome e lo stesso descrittore nella sua classe, quindi il primo proiettile non sparerà. Il secondo proiettile comunque sarà: c'è una superclasse e invoca il metodo del superA.
Il compilatore non lo incorpora e non esiste una copia del sorgente di Sup nella classe.
Tuttavia la storia non è ancora finita. Questo è solo ilcodice compilato . Una volta che il codice ha raggiunto la JVM, HotSpot può essere coinvolto.
Sfortunatamente, non ne so molto, quindi farò appello all'autorità su questo argomento e andrò a Inlining in Java dove si dice che HotSpot può incorporare metodi (anche metodi non finali).
Andando ai documenti si nota che se una particolare chiamata di metodo diventa un hot spot invece di fare quella ricerca ogni volta, queste informazioni possono essere incorporate - copiando efficacemente il codice da Sup methodA () in Sub methodA ().
Ciò viene eseguito in fase di esecuzione, in memoria, in base al comportamento dell'applicazione e alle ottimizzazioni necessarie per accelerare le prestazioni.
Come affermato in HotSpot Internals per OpenJDK "I metodi sono spesso incorporati. Le invocazioni statiche, private, finali e / o" speciali "sono facili da incorporare."
Se scavi nelle opzioni per la JVM troverai un'opzione di -XX:MaxInlineSize=35
(35 è il valore predefinito) che è il numero massimo di byte che possono essere incorporati. Sottolineerò che questo è il motivo per cui a Java piace avere molti piccoli metodi, perché possono essere facilmente incorporati. Quei piccoli metodi diventano più veloci quando vengono chiamati di più perché possono essere incorporati. E mentre si può giocare con quel numero e aumentarlo, si possono rendere meno efficaci altre ottimizzazioni. (domanda SO correlata: strategia di integrazione di HotSpot JIT che evidenzia una serie di altre opzioni per sbirciare gli interni di inline che HotSpot sta facendo).
Quindi no: il codice non è integrato al momento della compilazione. E sì: il codice potrebbe benissimo essere integrato durante l'esecuzione se le ottimizzazioni delle prestazioni lo giustificano.
E tutto ciò che ho scritto sull'instradamento di HotSpot si applica solo a HotSpot JVM distribuito da Oracle. Se guardi l'elenco delle macchine virtuali Java di wikipedia, ce ne sono molte di più oltre a HotSpot e il modo in cui tali JVM gestiscono l'inline può essere completamente diverso da quello che ho descritto sopra. Apache Harmony, Dalvik, ART - le cose potrebbero funzionare diversamente lì.