12
votes

Etat d'objet de classe dérivé lorsque le constructeur de la classe de base appelle la méthode remplacée dans Java

Veuillez vous reporter au code Java ci-dessous: xxx

La sortie vue est la suivante: xxx

Je pense que var = 0 se produit parce que l'objet est à moitié initialisé; Semblable à ce que Skeet Jon dit ici

Mes questions sont les suivantes:

Pourquoi la méthode remplacée est-elle appelée si l'objet de classe dérivé n'est pas encore créé?

à quel moment-là est varié de la valeur attribuée 0?

Y a-t-il des cas d'utilisation dans lesquels un tel comportement est souhaité?


4 Réponses :


12
votes
  • Le OBJECT OBJECT a été créé - c'est juste que le constructeur n'a pas encore été exécuté. Le type d'objet ne change jamais dans Java après que l'instant est créé, ce qui se passe avant que tous les constructeurs s'épuent.

  • var est attribué la valeur par défaut de 0 dans le processus de création d'un objet, avant que les constructeurs ne soient exécutés. Fondamentalement, la référence de type est définie et le reste de la mémoire représentant l'objet est essuyé à zéro (conceptuellement, de toute façon - il peut déjà avoir été essuyé à zéro avant, dans le cadre de la collecte des ordures)

  • Ce comportement au moins conduit à la cohérence, mais cela peut être une douleur. En termes de cohérence, supposons que vous ayez une sous-classe en lecture seule d'une classe de base mutable. La classe de base peut avoir une propriété Ismutable () qui a été effectivement défaillante sur true - mais la sous-classe lavérifie pour toujours retourner false. Il serait étrange que l'objet soit mutable avant que le constructeur de sous-classe ne courait, mais immutaculable ensuite. D'autre part, c'est définitivement étrange dans les situations où vous finissez par exécution de code dans une classe avant que le constructeur de cette classe ait fonctionné: (

    Quelques lignes directrices:

    • Essayez de ne pas faire beaucoup de travail dans un constructeur. Une façon d'éviter que ceci est de travailler dans une méthode statique, puis effectuez la dernière partie de la méthode statique un appel de constructeur qui définit simplement des champs. Bien sûr, cela signifie que vous n'obtiendrez pas les avantages du polymorphisme pendant que vous faites le travail - mais ce faisant dans un appel de constructeur serait dangereux de toute façon.

    • Essayez très difficile d'éviter les appels vers des méthodes non finales lors d'un constructeur - il est très susceptible de provoquer une confusion. Documenter toute méthode des appels que vous avez vraiment avez pour faire très clairement, afin que quiconque leur prenne saillie qu'ils seront appelés avant l'initialisation terminée.

    • Si vous devez appeler une méthode pendant la construction, il est généralement pas alors approprié de l'appeler ensuite. Si tel est le cas, documentez-le et tente de l'indiquer dans le nom.

    • Essayez de ne pas dépasser l'héritage en premier lieu - cela ne va pas devenir un problème lorsque vous avez une sous-classe dérivant d'une superclasse autre que l'objet :) La conception de l'héritage est délicate.


4 commentaires

Dans Swing, il est courant d'exécuter Créer la méthode dérivée avant que le constructeur [corps] ait fonctionné. Swing est définitivement étrange.


@TOM, ce qui signifie que la méthode créer peut ne jamais dépendre de l'état de l'objet de la classe dérivée.


@RSP YUP. Cela dépendra généralement du type de la classe dérivée. Il peut en réalité dépendre de l'état introduit à partir d'un "code extérieur ce " ou via un piratage tel que threadlocal .


Merci pour l'explication cogent!



2
votes

Il existe certaines propriétés de la spécification de langue Java qui devrait être notée afin d'expliquer ce comportement:


3 commentaires

Ce n'est pas vraiment la raison, car l'ordre de construction est le même en C ++. Je ne vois pas comment ça pourrait jamais être différent réellement. Pourtant, cette question ne se pose pas en C ++. La véritable raison est que l'objet est du type cible tout au long de la construction, qui n'est pas l'affaire en C ++.


@EJP: Je ne comparais pas avec C ++. Tout ce que je suis insulte, c'est que deux faits causent ce comportement: 1) Le SUPER'S COR est toujours appelé premier 2) Un appel à une méthode de la CTOR n'est pas différent de tout appel, il s'agit donc d'un appel virtuel à moins que la méthode est finale ( privé / déclaré comme final). Voir les liens que j'ai fournis pour plus de détails sur ce problème de conception.


Je suis d'accord avec les faits deux , maintenant vous les avez dit à la fois ;-)



5
votes

Pourquoi la méthode remplacée est-elle appelé si l'objet de classe dérivé n'est pas encore créé?

dérivé Constructeur de classe appelle implicitement le constructeur de la classe comme première instruction. BASE Constructeur de classe Méthode () QUI INVOTE La mise en œuvre répandue dans la classe DROITE car c'est la classe dont l'objet est créé. méthode () dans dérivé classe voit var comme 0 à ce point.

à quel moment-là est Var attribué Valeur 0?

var est attribué la valeur par défaut pour int type I.e. 0 avant que le controeur de dérivé classe est invoqué. Il est attribué la valeur de 2 après l'appel de la contruceur de superclasse implicite a fini et avant les énoncés dans dérivé constructeur de classe commence à exécuter.

Y a-t-il des cas d'utilisation où de tels Le comportement est souhaité?

Il s'agit généralement d'une mauvaise idée d'utiliser non- final non- Méthodes privées dans les constructeurs / initialiseurs d'un autre classique classe . Les raisons sont évidentes dans votre code. Si l'objet créé est une instance de sous-classe, les méthodes peuvent donner des résultats inattendus.


0 commentaires

3
votes

Notez que cela est différent de C ++, où le type change alors que l'objet est en cours de construction, de sorte que l'appelant une méthode virtuelle à partir des constructeurs de classe de base n'appelle pas le remplacement de la classe dérivée. La même chose arrive à l'inverse pendant la destruction. Donc, cela peut être un petit piège pour les programmeurs C ++ venant à Java.


1 commentaires

Oui, toujours bon de savoir que le type peut changer en C ++ et ne peut pas en Java.