Comencemos con dos clases simples:
package com.michaelt.so.supers;
public class Sup {
int methodA(int a, int b) {
return a + b;
}
}
y entonces
package com.michaelt.so.supers;
public class Sub extends Sup {
@Override
int methodA(int a, int b) {
return super.methodA(a, b);
}
}
Compilando el método A y mirando el código de bytes se obtiene:
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
Y puede ver allí con el método invokespecial que realiza la búsqueda contra el método de clase SupA ().
El código operativo invokespecial tiene la siguiente lógica:
- Si C contiene una declaración para un método de instancia con el mismo nombre y descriptor que el método resuelto, se invocará este método. El procedimiento de búsqueda termina.
- De lo contrario, si C tiene una superclase, este mismo procedimiento de búsqueda se realiza de forma recursiva utilizando la superclase directa de C. El método a invocar es el resultado de la invocación recursiva de este procedimiento de búsqueda.
- De lo contrario, se genera un AbstractMethodError.
En este caso, no existe un método de instancia con el mismo nombre y descriptor en su clase, por lo que la primera viñeta no se disparará. Sin embargo, la segunda viñeta sí: hay una superclase e invoca el método A de la super.
El compilador no incluye esto y no hay una copia de la fuente de Sup en la clase.
Sin embargo, la historia aún no ha terminado. Este es solo elcódigo compilado . Una vez que el código llega a la JVM, HotSpot puede involucrarse.
Desafortunadamente, no sé mucho al respecto, por lo que recurriré a la autoridad sobre este asunto e iré a Inlining in Java, donde se dice que HotSpot puede incorporar métodos en línea (incluso métodos no finales).
Al ir a los documentos , se observa que si una llamada a un método en particular se convierte en un punto caliente en lugar de hacer esa búsqueda cada vez, esta información se puede insertar, copiando efectivamente el código del método Sup A () en el método Sub A ().
Esto se realiza en tiempo de ejecución, en la memoria, según el comportamiento de la aplicación y las optimizaciones necesarias para acelerar el rendimiento.
Como se indica en HotSpot Internals para OpenJDK "Los métodos a menudo están en línea. Las invocaciones estáticas, privadas, finales y / o" especiales "son fáciles de incorporar".
Si profundiza en las opciones para la JVM , encontrará una opción de -XX:MaxInlineSize=35
(35 es el valor predeterminado) que es el número máximo de bytes que se pueden insertar. Señalaré que esta es la razón por la que a Java le gusta tener muchos métodos pequeños, porque se pueden insertar fácilmente. Esos pequeños métodos se vuelven más rápidos cuando se los llama más porque pueden estar en línea. Y aunque uno puede jugar con ese número y hacerlo más grande, puede causar que otras optimizaciones sean menos efectivas. (Pregunta SO relacionada: estrategia de línea HotSpot JIT que señala una serie de otras opciones para echar un vistazo a las partes internas de la línea que está haciendo HotSpot).
Entonces, no, el código no está en línea en el momento de la compilación. Y sí, el código podría muy bien insertarse en tiempo de ejecución si las optimizaciones de rendimiento lo justifican.
Y todo lo que he escrito sobre la incorporación de HotSpot solo se aplica a HotSpot JVM distribuido por Oracle. Si nos fijamos en la lista de máquinas virtuales Java de Wikipedia, hay muchos más que solo HotSpot y la forma en que esas JVM manejan la alineación puede ser completamente diferente de lo que he descrito anteriormente. Apache Harmony, Dalvik, ART: las cosas pueden funcionar de manera diferente allí.