44 votes

Comment fonctionne l'héritage dans ce code particulier?

 class A
{
    int a = 2, b = 3;
    public void display()
    {
        int c = a + b;
        System.out.println(c);
    }
}
class B extends A
{
    int a = 5, b = 6;
}
class Tester
{
    public static void main(String arr[])
    {
        A x = new A();
        B y = new B();
        x.display();
        y.display();
    }
}
 

Pourquoi la sortie est-elle 5,5? Et non 5,11? .Comment fonctionnerait la méthode y.display() ?

109voto

Jon Skeet Points 692016

pourquoi la sortie vient 5,5?

Parce qu' A.display() ne sait que sur les champs A.a et A.b. Ceux sont les seuls champs que le code en A connaît. On dirait que vous attendez les déclarations en B pour "contourner" le champ des déclarations. Ils n'en ont pas. Ils déclarent de nouveaux champs de masquer les champs existants. Les Variables ne se comportent pas pratiquement dans la façon dont les méthodes ne sont - le concept de remplacement d'une variable n'existe tout simplement pas. À partir de la JLS section 8.3:

Si la classe déclare un champ avec un certain nom, puis la déclaration de ce champ qui est dit pour cacher toutes et tous accessible déclarations de champs avec le même nom dans les super-classes, et superinterfaces de la classe.

Vous pouvez obtenir l'effet que vous souhaitez en changeant B , de sorte que son constructeur permet de modifier les valeurs des champs existants qu'il hérite de A à la place:

class B extends A {
    B() {
        a = 5;
        b = 6;
    }
}

Noter que ce ne sont pas les déclarations de variables. Ils sont juste des affectations. Bien sûr, dans la plupart des code (enfin, la plupart de code que j'ai vu en tout cas) les champs en A serait privé, et ne pouvais donc pas être accessible à partir de B, mais c'est juste exemple pour expliquer le comportement linguistique.

16voto

fabian Points 3742

Dans la classe A vous déclarez les champs a et b . La méthode display utilise ces champs. Dans la classe B vous déclarez de NOUVEAUX champs du même nom. En fait, vous cachez les anciens champs sans les "neutraliser". Pour affecter différentes valeurs aux mêmes champs, utilisez un constructeur:

 class A {
    A(int a, int b) {
        this.a = a;
        this.b = b;
    }

    A() {
        this(2, 3);
    }

    int a,b;

    public void display() {
        int c=a+b;
        System.out.println(c);
    }
}

class B extends A {
    B() {
        super(5, 6);
    }
}
 

13voto

Andy Points 1640

Quand vous faites cela:

class B extends A
{
    int a = 5, b = 6;
}

vous n'êtes pas redéfinir a et b, vous êtes à la création de nouvelles variables avec le même nom. Si vous vous retrouvez avec quatre variables( A.a, A.b, B.a, B.b).

Lorsque vous appelez display() et calculer la valeur de c, A.a et A.b , il ne faut pas B.a et B.b

9voto

Amit Sharma Points 667

Il n'y a rien que l'on appelle variable variable. C'est pourquoi vous obtenez le même résultat dans les deux cas.

6voto

La raison en est que Java utilise le concept de la portée lexicale de résolution variable.

Fondamentalement, il existe deux options possibles pour résoudre les variables libres dans une fonction ("libre" ne signifie pas local et n'est pas lié aux paramètres de la fonction):

1) contre l'environnement dans lequel la fonction est déclarée

2) à l'encontre de l'environnement dans lequel la fonction est exécutée (appelé)

Java va le premier, de façon variables libres dans les méthodes sont résolus [statiquement, lors de la compilation] à l'encontre de leur portée lexicale (environnement), qui comprend:

  • les paramètres de la méthode et locales variables de la méthode
  • champ des déclarations dans la classe contenant la méthode de déclaration
  • champ public déclarations dans la classe parent
  • et ainsi de suite, jusqu'à la chaîne de l'héritage

Vous verriez ce comportement mis en œuvre dans la plupart des langages de programmation, car il est transparent pour le développeur et aide à prévenir les erreurs des ombres de variables.

C'est l'opposé de la façon dont les méthodes de travail en Java:

class A {
    public void foo() {
        boo();
    }
    public void boo() {
        System.out.println("A");
    }
}
class B extends A {
    @Override
    public void boo() {
        System.out.println("B");
    }
}
class Main {
    public static void main(String[] args) {
        B b = new B();
        b.foo(); // outputs "B"
    }
}

Cette dynamique d'expédition: appel de la méthode est résolu dynamiquement lors de l'exécution à l'encontre de l'objet réel, sur lequel elle est appelée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X