it-swarm.com.de

Erläutern Sie, wie das Verbergen von Variablen in diesem Java-Code funktioniert

Beachten Sie den folgenden Code

class A
{
    int x = 5;
    void foo()
    {
        System.out.println(this.x);
    }
}
class B extends A
{
    int x = 6;
    // some extra stuff
}
class C
{
    public static void main(String args[])
    {
         B b = new B();
         System.out.println(b.x);
         System.out.println(((A)b).x);
         b.foo();
    }
 }  

Ausgabe des Programms ist 

6
5
5

Ich verstehe die ersten beiden, kann mich aber nicht mit den letzten beiden befassen. Wie druckt b.foo () 5. Die Klasse B erbt die Methode foo. Aber sollte es nicht drucken, was b.x drucken würde? Was genau passiert hier?

21
Parzival

Ja, die B-Klasse erbt die foo-Methode. Die Variable x in B verbirgt die x in A; es ersetzt es nicht.

Dies ist eine Frage des Umfangs. Die foo-Methode in A sieht nur die im Geltungsbereich befindlichen Variablen. Die einzige Variable im Gültigkeitsbereich ist die Instanzvariable x in A.

Die foo-Methode wird in B vererbt, aber nicht überschrieben. Wenn Sie foo explizit mit demselben exakten Code überschreiben würden:

class B extends A
{
    int x = 6;

    @Override
    void foo()
    {
        System.out.println(this.x);
    }
}

Dann wäre die Variable, die sich im Geltungsbereich befinden würde, wenn auf this.x verwiesen wird, Bs x, und 6 würde gedruckt. Obwohl der Text der Methode derselbe ist, unterscheidet sich der Verweis aufgrund des Umfangs.

Wenn Sie wirklich auf As x in der B-Klasse verweisen möchten, können Sie super.x verwenden.

18
rgettman

Felder sind in Java nicht überschreibbar und Unterklassen mit denselben Feldnamen wie der übergeordnete Klassenschatten "nur" die Felder der übergeordneten Klasse.
this.x bezieht sich also auf die x, die in der aktuellen Klasse definiert ist: A.
Das Ergebnis: 5

Genauer gesagt: Die foo()-Methode wird von der B-Unterklasse geerbt. Dies bedeutet jedoch nicht, dass sich das Verhalten der geerbten Methode bei Instanzfeldern ändert, auf die verwiesen wird, da diese Felder nicht überschrieben werden können: Der this.x-Ausdruck, auf den das A.x-Feld verweist Die foo()-Methode referenziert weiterhin A.x

Es ist genau das gleiche wie bei den beiden vorherigen Aussagen: 

 B b = new B();
 System.out.println(b.x); // refers B.x -> 6
 System.out.println(((A)b).x); // refers A.x -> 5
 b.foo(); // refers under the hood A.x -> 5

Die sehr gute Antwort von rgettman zeigt, wie Sie das in der Unterklasse versteckte Feld überwinden können.
Eine Alternative zur Überwindung des Verdeckens besteht darin, das Instanzfeld private (das empfohlen wird) zu erstellen und eine Methode bereitzustellen, die den Wert zurückgibt.
Auf diese Weise profitieren Sie von dem übergeordneten Mechanismus, und das Feldverstecken ist für Kunden der Klassen kein Thema mehr:

class A
{
    private int x = 5;

    int getX(){
        return x;
    }

    void foo()
    {
        System.out.println(this.getX());
    }
}
class B extends A
{
    private int x = 6;

    int getX(){
        return x;
    }
}
2
davidxxx

Nun, das liegt an der statischen Bindung.

1) Statische Bindung in Java tritt während der Kompilierzeit auf, während Dynamic Die Bindung erfolgt zur Laufzeit.

2) private Methoden, endgültige Methoden und statische Methoden und Variablen verwendet statische Bindung und wird vom Compiler gebunden, während virtuelle Methoden .__ sind. zur Laufzeit basierend auf Laufzeitobjekt verbunden.

3) Statische Bindung verwendet Typinformationen (Klasse in Java) zum Binden Die dynamische Bindung verwendet Object, um die Bindung aufzulösen.

4) Überladene Methoden werden unter Verwendung der statischen Bindung verbunden, während sie überschrieben werden Methoden werden zur Laufzeit mittels dynamischer Bindung verbunden.

2
Michel_T.

In Java können Methoden überschrieben werden, Variablen nicht. Da Ihre Methode foo in B nicht überschrieben wird, wird die Member-Variable von A übernommen.

1
Anatolii

Wenn du anrufst 

b.foo(); 

Sie prüft, ob B die Methode foo() überschrieben hat, die sie nicht hat. Sie sucht dann eine Ebene nach der Oberklasse A und ruft diese Methode auf.

Sie haben dann die Version von foo() von A aufgerufen, die dann ausgedruckt wird 

this.x

Nun kann A die Version von B von x nicht sehen.


Um dies zu lösen, müssen Sie die Methode in B überschreiben.

class B extends A
{
    int x = 6;

    @Override
    void foo()
    {
        System.out.println(this.x);
    }

}

Jetzt anrufen

b.foo();

ruft die B-Version von foo() auf und Sie erhalten das erwartete Ergebnis.

0
Andreas DM