La clase Sub
es una subclase de clase Sup
. ¿Qué significa eso prácticamente? O, en otras palabras, ¿cuál es el significado práctico de "herencia"?
Opción 1: el código de Sup se copia virtualmente en Sub. (como en 'copiar y pegar', pero sin el código copiado visualmente visto en la subclase).
Ejemplo: methodA()
es un método originalmente en Sup. Sub extiende Sup, por lo que methodA()
se copia (virtualmente) en Sub. Ahora Sub tiene un método llamado methodA()
. Es idéntico a Sup methodA()
en cada línea de código, pero pertenece completamente a Sub, y no depende de Sup o está relacionado con Sup de ninguna manera.
Opción 2: el código de Sup no se copia en realidad en Sub. Todavía está solo en la superclase. Pero se puede acceder a ese código a través de la subclase y puede ser utilizado por la subclase.
Ejemplo: methodA()
es un método en Sup. Sub extiende Sup, por lo que ahora methodA()
se puede acceder a través de sub modo: subInstance.methodA()
. Pero eso en realidad invocará methodA()
en la superclase. Lo que significa que el método A () operará en el contexto de la superclase, incluso si fue llamado por la subclase.
Pregunta: ¿Cuál de las dos opciones es realmente cómo funcionan las cosas? Si ninguno de ellos lo es, entonces describa cómo funcionan realmente estas cosas.
fuente
Respuestas:
Opcion 2.
El bytecode se referencia dinámicamente en tiempo de ejecución: esta es la razón por la cual, por ejemplo, se producen LinkageErrors .
Por ejemplo, suponga que compila dos clases:
Ahora modifique y vuelva a compilar la clase principal sin modificar o volver a compilar la clase secundaria :
Finalmente, ejecute un programa que use la clase secundaria. Recibirá un NoSuchMethodError :
fuente
Comencemos con dos clases simples:
y entonces
Compilando el método A y mirando el código de bytes se obtiene:
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:
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í.
fuente
el código no se copia, se accede por referencia:
los compiladores pueden optimizar cómo se representa / ejecuta esto en la memoria, pero esa es básicamente la estructura
fuente