Con una tale domanda, l'esame SCJP sta valutando la tua conoscenza di ciò che è noto come che nasconde. L'esaminatore ha deliberatamente complicato le cose per cercare di farti credere che il comportamento del programma dipende solo dal polimorfismo, che non è così.
Proviamo a rendere le cose un po 'più chiare mentre rimuoviamo il metodo addFive()
.
class Foo {
public int a = 3;
}
class Bar extends Foo {
public int a = 8;
}
public class TestClass {
public static void main(String[]args) {
Foo f = new Bar();
System.out.println(f.a);
}
}
Ora le cose sono un po 'meno confuse.Il metodo main
dichiara una variabile di tipo Foo
, a cui viene assegnato un oggetto di tipo Bar
in fase di esecuzione. Questo è possibile dal momento che Bar
eredita da Foo
. Il programma fa quindi riferimento al campo pubblico a
della variabile di tipo Foo
.
L'errore qui è di credere che lo stesso tipo di concetto noto come che sostituisce si applica ai campi di classe. Ma non c'è un concetto per i campi: il campo pubblico a
di classe Bar
non imperativa è il campo pubblico a
di classe Foo
ma fa quello che viene chiamato nasconde. Come suggerisce il nome, significa che nell'ambito della classe Bar
, a
si riferirà al campo Bar
che non ha nulla a che fare con quello di Foo
. (JLS 8.4.8 - Inheritance, Overriding, and Hiding)
Quindi, quando stiamo scrivendo f.a
, a quale a
ci riferiamo? Ricordiamo che la risoluzione del campo a
viene eseguita al tempo di compilazione utilizzando il tipo di dichiarazione dell'oggetto f
, che è Foo
. Di conseguenza, il programma stampa "3".
Ora, aggiungiamo un metodo addFive()
nella classe Foo
e lo sovrascriviamo nella classe Bar
come nella domanda d'esame. Qui si applica il polimorfismo, pertanto la chiamata f.addFive()
viene risolta utilizzando non il tempo di compilazione ma il tipo di runtime dell'oggetto f
, che è Bar
, e quindi è stampato "b".
Ma c'è ancora qualcosa che dobbiamo capire: perché il campo a
, che è stato incrementato di 5 unità, si attacca ancora al valore '3'? Qui nascondersi sta giocando in giro. Poiché questo è il metodo della classe Bar
che viene chiamato e poiché nella classe Bar
, ogni a
si riferisce al campo pubblico Bar
a
, questo è in realtà il campo Bar
che viene incrementato.
1) Ora, una domanda sussidiaria: come potremmo accedere Campo pubblico s' il Bar
a
dal metodo main
? Possiamo farlo con qualcosa di simile:
System.out.println(((Bar)f).a);
che costringono il compilatore per risolvere il membro campo a
della f
come Bar
s' a
campo.
Questo dovrebbe stampare 'b 13' nel nostro esempio.
2) Ancora un'altra domanda: Come potremmo aggirare nasconde in addFive()
metodo della classe Bar
per riferirsi non a
campo s' il Bar
, ma al suo campo eponimous superclasse?Basta aggiungere la parola chiave super
davanti al riferimento di campo fa il trucco:
public void addFive() {
super.a += 5;
System.out.print("b ");
}
Ciò stampare 'b 8' nel nostro esempio.
Notare che l'affermazione iniziale
public void addFive() {
this.a += 5;
System.out.print("b ");
}
potrebbe essere raffinato per
perché quando il compilatore sta risolvendo il campo a
, si inizierà a guardare nel perimetro che racchiude più vicino all'interno del metodo addFive()
e trovare l'istanza della classe Bar
, eliminando la necessità di utilizzare esplicitamente this
.
Ma, beh, this
era probabilmente un indizio per il candidato per risolvere questa domanda d'esame!
Questa è una domanda riguardante SCJP, giusto? –
yep @PrakharMohan sei apparso anche per lo stesso ??? non ho ancora ... :) –