La classe Sub
est une sous-classe de classe Sup
. Qu'est-ce que cela signifie pratiquement? Ou en d'autres termes, quelle est la signification pratique de "l'héritage"?
Option 1: le code de Sup est virtuellement copié dans Sub. (comme dans «copier-coller», mais sans le code copié visible visuellement dans la sous-classe).
Exemple: methodA()
est une méthode originellement dans Sup. Sub étend Sup, il methodA()
est donc (virtuellement) copié-collé sur Sub. Maintenant, Sub a une méthode nommée methodA()
. Il est identique à Sup methodA()
dans chaque ligne de code, mais appartient entièrement à Sub - et ne dépend pas de Sup ou n'est lié à Sup en aucune façon.
Option 2: le code de Sup n'est pas réellement copié dans Sub. Ce n'est toujours que dans la superclasse. Mais ce code est accessible via la sous-classe et peut être utilisé par la sous-classe.
Exemple: methodA()
est une méthode dans Sup. Sous étend Sup, maintenant methodA()
accessible via Sub comme ceci: subInstance.methodA()
. Mais cela va en fait être invoqué methodA()
dans la superclasse. Ce qui signifie que methodA () fonctionnera dans le contexte de la superclasse, même si elle a été appelée par la sous-classe.
Question: Laquelle des deux options est vraiment la façon dont les choses fonctionnent? Si aucun d'entre eux ne l'est, veuillez décrire comment ces choses fonctionnent réellement.
la source
Réponses:
Option 2.
Le bytecode est référencé dynamiquement lors de l'exécution: c'est pourquoi, par exemple, LinkageErrors se produit.
Par exemple, supposons que vous compiliez deux classes:
Modifiez et recompilez maintenant la classe parent sans modifier ni recompiler la classe enfant :
Enfin, exécutez un programme qui utilise la classe enfant. Vous recevrez une NoSuchMethodError :
la source
Commençons par deux classes simples:
et alors
En compilant la méthode A et en regardant le code d'octet, on obtient:
Et vous pouvez voir juste là avec la méthode invokespecial qu'il fait la recherche contre la méthode de classe SupA ().
L' opcode invokespecial a la logique suivante:
Dans ce cas, il n'y a pas de méthode d'instance avec le même nom et le même descripteur dans sa classe, donc la première puce ne va pas se déclencher. La deuxième puce le fera cependant - il y a une superclasse et elle invoque la méthode A du super.
Le compilateur n'inline pas cela et il n'y a pas de copie de la source de Sup dans la classe.
Mais l'histoire n'est pas encore terminée. Ce n'est que lecode compilé . Une fois que le code atteint la JVM, HotSpot peut s'impliquer.
Malheureusement, je ne sais pas grand-chose à ce sujet, je vais donc faire appel à l'autorité à ce sujet et aller à Inlining à Java où il est dit que HotSpot peut incorporer des méthodes (même des méthodes non définitives).
En allant dans la documentation, il est à noter que si un appel de méthode particulier devient un point chaud au lieu de faire cette recherche à chaque fois, ces informations peuvent être intégrées - en copiant efficacement le code de Sup methodA () dans Sub methodA ().
Cela se fait au moment de l'exécution, en mémoire, en fonction du comportement de l'application et des optimisations nécessaires pour accélérer les performances.
Comme indiqué dans HotSpot Internals for OpenJDK "Les méthodes sont souvent intégrées. Les invocations statiques, privées, finales et / ou" spéciales "sont faciles à intégrer."
Si vous creusez dans les options de la JVM, vous trouverez une option
-XX:MaxInlineSize=35
(35 étant la valeur par défaut) qui est le nombre maximal d'octets pouvant être insérés. Je soulignerai que c'est pourquoi Java aime avoir beaucoup de petites méthodes - car elles peuvent être facilement intégrées. Ces petites méthodes deviennent plus rapides lorsqu'elles sont appelées davantage car elles peuvent être intégrées. Et bien que l'on puisse jouer avec ce nombre et l'agrandir, cela peut rendre d'autres optimisations moins efficaces. (question SO connexe: stratégie d'inclusion de HotSpot JIT qui souligne un certain nombre d'autres options pour jeter un œil aux aspects internes de l'inclusion que HotSpot fait).Donc, non - le code n'est pas inséré au moment de la compilation. Et, oui - le code pourrait très bien être intégré à l'exécution si les optimisations de performances le justifient.
Et tout ce que j'ai écrit sur l'incrustation HotSpot s'applique uniquement à la machine virtuelle Java HotSpot distribuée par Oracle. Si vous regardez la liste des machines virtuelles Java de wikipedia, il y a bien plus que HotSpot et la façon dont ces JVM gèrent l'inline peut être complètement différente de ce que j'ai décrit ci-dessus. Apache Harmony, Dalvik, ART - les choses peuvent fonctionner différemment là-bas.
la source
le code n'est pas copié, il est accessible par référence:
les compilateurs peuvent optimiser la façon dont cela est représenté / exécuté en mémoire, mais c'est essentiellement la structure
la source