piątek, 18 kwietnia 2008

Java Killers #001

Witam w pierwszym (i mam nadzieje nie ostatnim) odcinku z cyklu
Java Killers. JK to światowa organizacja, która na cel bierze sobie zbicie z tropu każdego programistę, który uważa się za Javowca. Java Killers przyjmują wiele form, spotkacie ich w http://javapuzzlers.com/ czy też na rozmowie kwalifikacyjnej o pracę. To elitarna grupa, która chce udowodnić tylko jedno - że nie znasz Javy.
Wasza broń to te posty! Poznajcie wroga lepiej teraz niż na przykład na rozmowie o pracę. W cyklu tym na światło dzienne wyjdą pytania (oraz odpowiedzi), których pewnie nie spotkacie na Sun Certificated Java Programmer. To pytania wytrącające z pantałyku, powodujące salwy śmiechu i panicznej histerii. Niemniej jednak powinny Wam również dostarczyć zabawy oraz uciechy. Mimo wszystko potraktujcie je jak najbardziej poważnie, są zabójcze...

Dostatecznie zaintrygowani? Ok, a więc bez zbędnych wstępów przejdźmy do odcinka dzisiejszego. Poznajmy dwie klasy o wdzięcznych nazwach: Foo i Bar, gdzie klasa Bar dziedziczy po Foo:

package javakillers.part001;

public class Foo
{
public int a;

public Foo()
{

a = 0;
}

public void add()
{
a = a + 10;

}

}

package javakillers.part001;

public class Bar extends Foo
{
public int a;


public Bar()
{
a = 2;
}


@Override
public void add()
{
a = a + 5;
}
}

Wszystko wydaje się być proste i intuicyjne prawda? Klasa Bar nadpisuje metodę add z klasy Foo, dodatkowo sama w konstruktorze inicjalizuje zmienną a. Zatem pytanie brzmi, co zwróci poniższy kod:

public static void main(String[] args)
{
Foo f = new Bar();
f.add();
System.out.println("a = " + f.a);
System.out.println("a w Bar = " + ((Bar)f).getA());
}

Odpowiedzi do wyboru macie cztery:

A) a = 0
B) a = 7
C) a = 5
D) a = 12





Ok, gotowi? A więc prawidłowa odpowiedź to:


A) a = 0


Zadacie pewnie pytanie "Że co proszę?" Poprawna odpowiedź wydaję się każda, tylko nie zero. Przecież wywołujemy metode add() i niezależnie czy wywołana zostanie metoda z klasy Foo czy nadpisująca ją metoda z klasy Bar, zawsze zmienna a ma dodaną do siebie jakąś wartość (10 lub 5). Zatem czemu wynik końcowy zero?

Diabeł jak zwykle tkwi w szczegółach. Tworząc w klasie Bar ponownie zmienną a

public class Bar extends Foo
{
public int a;

...

ukrywamy zmienną a z klasy Foo. W kodzie klasy Bar mamy de facto dwie zmienne a. Ponieważ tylko do jednej możemy się odwołać, domyślnie jest to zmienna, która zdeklarowana była ostatnia. Innymi słowy tracimy bezpośredni dostęp do zmiennej a, którą odziedziczyliśmy po klasie Foo.
Teraz już wszystko wydawać powinno się jasne. W konstruktorze klasa Bar inicjaliuzję tą drugą zmienną a do wartości 2. Wywołanie metody add powoduje uruchomienie kodu

a = a + 5;

a zatem wartość zmiennej a w obiekcie klasy Bar przyjmuje wartość 7. Zauważamy, że wartość a z klasy Foo zostaje wciąż niezmieniona, a poniważ jest polem publicznym i mamy do niej pełny dostęp, kod

System.out.println("a = " + f.a);

drukuje wartość 'a = 0' (zwróćmy uwagę na fakt, że deklaracja obiektu new Bar wygląda następująco: Foo f = new Bar();).

Zatem pozostaje pytanie jak się przed tym bronić? Dwie ważne sprawy:

  • Nie używać zmiennych publicznych
Generalnie jest to całkowite pogwałcenie zasady enkapsulacji, co jak widać może mieć poważne konsekwancje.
  • Nie używać nazw zmiennych z klas nadrzędnych
Użycie w deklaracji zmiennej nazwy innej zmiennej, odziedziczonej od rodzica, przysłania tą oryginalną zmienną. Dobre środowisko developerskie powinno wykryć tą zależność i powiadomić w warningach o zaistniałej sytuacji.
Nie mniej nie powinniśmy w 100% polegać na IDE, dlatego zawsze warto zwrócić szczególną uwagę przy nadawaniu nazw zmiennym naszej klasy.

I to już koniec na dziś odcinka z serii Java Killers. Znaliście poprawną odpowiedź?

4 komentarze:

Anonimowy pisze...

Niestety na identycznym pytaniu poległem na przedmiocie o ironicznej nazwie Wstęp do java :P

Paweł Szulc pisze...

Coż, widać słowko "wstęp" było szeroko rozumiane. Polecam czytać kolejne wpisy w Java Killers, moze next time bedzie lepiej.

Pozdrawiam serdecznie

mzdz pisze...

Ha, wiedziałem! Niebawem chcę podejść do SCJP, trochę mnie to pokrzepiło.. :) Kiedy następny odcinek?

Paweł Szulc pisze...

No to gratuluje :) Następny odcinek z serii JK jakos w czwartek lub piatek.