variabile - Spiega come funziona il nascondimento delle variabili in questo codice Java




scala linguaggio pdf (4)

Bene, questo è dovuto al legame statico.

1) Il legame statico in Java si verifica durante il tempo di compilazione mentre l'associazione dinamica si verifica durante il runtime.

2) metodi privati, metodi finali e metodi e variabili statici utilizzano il binding statico e il legame con il compilatore mentre i metodi virtuali vengono uniti durante il runtime in base all'oggetto runtime.

3) Il binding statico utilizza le informazioni Type (Class in Java) per il binding mentre il binding dinamico utilizza Object per risolvere il binding.

4) I metodi con overload sono legati usando il binding statico mentre i metodi sottoposti a override vengono uniti mediante l'associazione dinamica in fase di esecuzione.

Considera sotto il codice

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();
    }
 }  

L'output del programma è

6
5
5

Capisco i primi due ma non riesco a capire l'ultimo. In che modo b.foo () print 5. B class erediterà il metodo foo. Ma non dovrebbe stampare ciò che bx avrebbe stampato? Cosa sta succedendo esattamente qui?


I campi non sono sovrascrivibili in Java e le sottoclassi con lo stesso nome campo della classe genitore ombreggiano "solo" i campi della classe genitore.
Quindi this.x riferisce alla x definita nella classe corrente: A
Considerando che il risultato: 5 .

Per essere più precisi: il metodo foo() è ereditato dalla sottoclasse B ma non significa che il comportamento del metodo ereditato cambierà sui campi di istanza a cui si fa riferimento poiché i campi detti non sono sovrascrivibili: l'espressione this.x che fa riferimento a il campo Ax nel metodo foo() continua a fare riferimento a Ax .

È esattamente la stessa cosa delle due precedenti affermazioni:

 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

L'ottima risposta di rgettman mostra come superare il campo nascosto nella sottoclasse.
Un'alternativa per superare l'occultamento si basa sul rendere private campo dell'istanza (che è consigliato) e fornire un metodo che restituisca il valore.
In questo modo beneficiate del meccanismo di override e il nascondiglio del campo non è più un problema per i clienti delle classi:

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;
    }
}

Quando chiami

b.foo(); 

Controlla se B ha scavalcato il metodo foo() , che non ha. Quindi guarda un livello in alto, alla superclasse A e invoca quel metodo.

Hai quindi invocato la versione di A di foo() che poi stampa

this.x

Ora, A non può vedere la versione di B di x .

Per risolvere questo, devi sovrascrivere il metodo in B

class B extends A
{
    int x = 6;

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

}

Ora, chiama

b.foo();

chiamerà la versione di B di foo() e otterrai il risultato atteso.


Sì, la classe B eredita il metodo foo . Ma la variabile x in B nasconde la x in A ; non lo sostituisce.

Questa è una questione di scopo. Il metodo foo in A vede solo le variabili che sono in ambito. L'unica variabile nell'ambito è la variabile di istanza x in A

Il metodo foo è ereditato, ma non sovrascritto, in B Se dovessi sovrascrivere esplicitamente foo con lo stesso codice esatto:

class B extends A
{
    int x = 6;

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

Quindi la variabile che sarebbe in ambito quando indicato da this.x sarebbe B x , e 6 verrebbe stampato. Mentre il testo del metodo è lo stesso, il riferimento è diverso a causa dell'ambito.

Per inciso, se davvero volevi fare riferimento alla classe A di x nella classe B , puoi usare super.x .





inheritance