Z takim pytaniem, egzamin SCJP ocenia Twoją wiedzę o tym, co jest znane pod nazwą , ukrywając numer. Egzaminator celowo komplikował rzeczy, aby spróbować uwierzyć, że zachowanie programu zależy tylko od polimorfizmu, którego nie ma.
Spróbujmy wyjaśnić sytuację, usuwając metodę 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);
}
}
Teraz sprawy są nieco mniej zagmatwane.Metoda main
deklaruje zmienną typu Foo
, której przypisano obiekt typu Bar
w czasie wykonywania. Jest to możliwe, ponieważ Bar
dziedziczy po Foo
. Następnie program odwołuje się do publicznego pola a
zmiennej typu Foo
.
Błąd polega na stwierdzeniu, że ten sam rodzaj pojęcia, znany jako przesłanianie, dotyczy pól klasy. Ale nie ma takiej koncepcji pola: pole publicznego a
klasy Bar
nie nadrzędnym jest pole publicznego a
klasy Foo
ale robi to co nazywa ukrywanie. Jak sama nazwa wskazuje, oznacza to, że w zakresie klasy Bar
, a
będzie odnosić się do własnego pola, które nie ma nic wspólnego z . (JLS 8.4.8 - Inheritance, Overriding, and Hiding)
Tak więc, kiedy piszemy f.a
, do którego odnosimy się: a
? Przypomnijmy, że rozdzielczość pola a
jest wykonywana w czasie kompilacji przy użyciu typu deklaracji obiektu f
, który jest Foo
. W konsekwencji program wypisze "3".
Teraz dodajmy metodę addFive()
do klasy Foo
i zastąpmy ją klasą Bar
, tak jak w pytaniu do egzaminu. Tutaj stosuje się polimorfizm, dlatego wywołanie f.addFive()
jest rozwiązywane przy użyciu nie czasu kompilacji, lecz typu środowiska wykonawczego obiektu f
, który jest Bar
, a zatem jest drukowany "b".
Ale jest jeszcze coś, co musimy zrozumieć: dlaczego pole a
, które zostało zwiększone o 5 jednostek, nadal trzyma się wartości "3"? Tutaj ukrywanie jest odtwarzane. Ponieważ jest to metoda klasy Bar
, która jest wywoływana, a ponieważ w klasie Bar
, każde a
odnosi się do publicznego pola , to jest to faktycznie pole Bar
, które jest inkrementowane.
1) Teraz jedna kwestia zależna: w jaki sposób możemy uzyskać dostęp do Bar
„s pole publicznego a
od sposobu main
? Możemy zrobić coś podobnego:
System.out.println(((Bar)f).a);
który zmusić kompilator rozwiązać członkiem dziedzinie a
od f
jako Bar
„s a
dziedzinie.
To mogłoby wydrukować "b 13" w naszym przykładzie.
2) Kolejna kwestia: jak moglibyśmy obejść ukrywanie w addFive()
metody klasy Bar
do odnoszą się nie do a
polu należy Bar
„s, ale jej nadklasy dziedzinie eponimous?Wystarczy dodanie słowa kluczowego super
przed odniesieniem pola załatwia sprawę:
public void addFive() {
super.a += 5;
System.out.print("b ");
}
Byłoby to print „b” 8 w naszym przykładzie.
Uwaga że początkowe oświadczenie
public void addFive() {
this.a += 5;
System.out.print("b ");
}
może być doprecyzowana do
bo gdy kompilator jest rozwiązywanie pole a
, zacznie szukać w najbliższym zakresu osłaniającego od obrębie metoda addFive()
i znajdź instancję klasy Bar
, co eliminuje konieczność użycia explicitely this
.
Ale, cóż, this
było prawdopodobnie wskazówką dla zdających, aby rozwiązać to pytanie egzaminacyjne!
To jest pytanie dotyczące SCJP, prawda? –
yep @PrakharMohan czy pojawiłeś się również w tym samym ??? Jeszcze nie ... :) –