12
votes

Une légère confusion concernant le remplacement des variables concernées

Je me prépare pour le SCJP (récemment rebrandé comme OCPJP par Oracle) et une question particulière que je me suis trompé sur un examen simulée m'a confondu, la description de réponse n'explique pas assez les choses assez claires.

Ceci est La question: xxx

la réponse est 5 , mais j'ai choisi 6 .

i comprendre que le dépassement s'applique aux méthodes d'exécution, et non aux variables, mais la façon dont mon esprit a interprété que println était:

  1. Call GetObject sur C1
  2. C1 est en fait un objet inférieur objet et a une substitution valide Pour getObject () , utilisez donc la méthode de remplacement
  3. Le remplacement de la substitution B, donc grab x de B qui est 6

    est-ce un cas de la JVM ignorant la pièce getObject () , et prenant toujours x à partir de c1 comme variables sont associés au moment de la compilation?


2 commentaires

Après avoir tapé le code, pourquoi ne pas l'exécuter et voir qu'il retourne 5?


Je vois aussi qu'il retournera 5 pas 6 !!


6 Réponses :


12
votes

Bien que le remplacement soit effectué correctement pour SubcovariAtTest, la réponse est 5 en raison de la déclaration de la variable C1. Il est déclaré comme un covarytest et non comme un subcovarantest.

Quand c1.getObject (). X est exécuté, il ne sait pas qu'il s'agit d'un sous-notetTest (aucun casting n'a été utilisé). C'est pourquoi 5 est renvoyé de Covariantest et non à 6 de SubcovariantTest. P>

Si vous modifiez P>

System.out.println(((SubCovariantTest) c1).getObject().x);


5 commentaires

Es-tu sûr? Je suis sûr que tout le point de polymorphisme est de pouvoir faire quelque chose comme ceci: peinture [] peinture = {nouveau redpaint (), nouveau bluepaint (), nouveau vertpaint ()}; ' et ensuite avoir pour (peinture p: peinture) peinture.getcolor (); `où chaque sous-classe de peinture a une substitution valide pour getcolor () . Chacun devrait fonctionner différemment, quel que soit sa connaissance de la sous-classe ou de ne pas être jeté.


Oui, mais les champs ne sont pas polymorphes en Java. Seules les méthodes sont. Le X dans la sous-classe cache le x dans la classe de base. Cela ne le remplace pas. Et en plus d'encapsulation, c'est une autre bonne raison de ne pas utiliser de champs publics.


Oh je vois. Intéressant! Je n'ai jamais su cela. Vous devriez ajouter cela à la réponse. :)


Merci@scott pour explication. Je cherchais juste un moyen d'accéder à la variable de Superclass via un tel code similaire. Toute idée Comment pourrions-nous utiliser super dans cette sortie et obtenir la même sortie?


utiliser super.varibalename



3
votes

Vous appelez la méthode à partir de C1 code>: system.out.println (c1.getObject (). x); code>

Type de référence C1 est: P >

public class CovariantTest 
{
    public A getObject() 
    {
       return new A();
    } 
    public static void main(String[]args) 
    {
       CovariantTest c1 = new SubCovariantTest();
       System.out.println(c1.getObject().x);
    }
}


0 commentaires

4
votes

Le terme technique pour ce qui se passe ici est "cacher". Les noms de variables en Java sont résolus par le type de référence, pas l'objet qu'ils référencent.

  • Un objet a une variable A.X.
  • B Objet a des variables A.X et B.x.

    Cependant, les méthodes d'instance avec la même signature sont "remplacées" non "cachées", et vous ne pouvez pas accéder à la version d'une méthode qui est remplacée de l'extérieur.

    Note qui se cache aussi S'applique aux méthodes statiques avec la même signature.

    Votre question maquette sous une forme simplifiée (sans remplacement): xxx


1 commentaires

Donc, pour les méthodes statiques, pouvons-nous dire que ma classe d'enfant B possède 2 méthodes statiques, A.StaticMethod () & B.StaticMethod ()? Autant que je sache, les membres statiques et les variables ne sont pas hérités ..



6
votes

D'accord, je sais que c'est un peu en retard pour répondre à cette question, mais moi et mon ami avaient le même problème et les réponses déjà ici ne le disaient pas vraiment pour nous. Je vais donc simplement indiquer quel problème j'avais et comment cela a du sens maintenant :)

Maintenant, je comprends que les champs ne sont pas annulés, mais ils se cachent que Miller.bartark a souligné et je comprends aussi que le dépassement est Pour les méthodes et non les champs que Scott souligne.

Le problème que j'ai cependant été ceci. Selon moi, xxx

Ceci doit transformer en: xxx

et qui évalue à 6. < P> Et je n'ai pas pu obtenir pourquoi la variable de classe A (super-classe) est appelée par un objet de classe B (sous-classe) sans avoir explicitement demandé un tel comportement. < / p>

et deviner du libellé de la question, je pense que l'OP avait la même question / le même doute à l'esprit.


Ma réponse:

Vous obtenez une pointe de la réponse d'Elbek. Placez les lignes suivantes dans la méthode principale et essayez de compiler le code: xxx

Vous remarquerez que la ligne 1 est complètement légale, tandis que la ligne 2 donne une erreur de compilation.

Ainsi, lorsque la fonction getObject () est appelée, la fonction CovariantTest (Super) est inversée par la fonction SubcovarAntTest (Sub) depuis sa validité du code et C1.GetObject () retournera nouveau B () .

Cependant, étant donné que la superficie renvoie une référence de type de classe A, même après avoir été annulée, elle doit renvoyer une référence de type de classe A à sauf si nous tapez -Int-le. Et ici, la classe B est une classe A (due à l'héritage).

SO Pratiquement, ce que nous obtenons de C1.GetObject () n'est pas < pré> xxx

mais ceci: xxx

C'est pourquoi la sortie est comprise à 5, même si un objet de la classe B est renvoyé et la classe B a une valeur de x comme 6.


1 commentaires

Droite, car pour Java version 5.0 et plus tard, le Covariant primordial est devenu une fonctionnalité de langue. Cette nouvelle fonctionnalité permet de remplacer une méthode par une méthode de classe dérivée qui a la même signature, mais un type de retour différent, tant que la méthode dérivée du type Retour est dérivée du type de retour de la méthode de remplacement. Donc, comme expliqué ci-dessus, lorsqu'une variable dont le type est CovariantTest est attribuée une instance de SubcovarAntTest, la valeur renvoyée par GeTObject () sera en effet une instance de B, mais elle sera couplée à la classe A pour correspondre au type de retour de GetObject. () à Covariantest.



0
votes

Lorsque des méthodes sont remplacées, des méthodes de sous-classe sont appelées, et lorsque des variables sont remplacées, les variables de superclasse sont utilisées


0 commentaires

0
votes

Lorsque la classe enfant et parent a tous deux une variable avec la variable variable de la classe de la classe enfant de la même catégorie de la classe enfant et celle-ci s'appelle la dissimulation variable.

Bien que la cachette variable ressemble à une variable une variable similaire à la méthode primordiale, mais ce n'est pas le cas, il n'est pas applicable uniquement aux méthodes lors de la masquage des variables applicables.

Dans le cas de la méthode de remplacement, les méthodes remplacées remplacent complètement les méthodes héritées afin que nous essayons d'accéder à la méthode de la référence des parents en maintenant l'objet de l'enfant, la méthode de la classe enfant est appelée.

mais en classe variable de la classe enfant masque les variables héritées au lieu de remplacer, alors lorsque nous essayons d'accéder à la variable de la référence des parents en maintenant l'objet de l'enfant, il sera accessible à partir de la classe mère.

Lorsqu'une variable d'instance dans une sous-classe a le même nom que la variable d'instance dans une superclasse, la variable d'instance est choisie parmi le type de référence.

Vous pouvez en savoir plus sur mon article Qu'est-ce que Ombrage variable et caché en Java.


0 commentaires