Spis treści
Zakres metod¶
W podrozdziale Instrukcji Warunkowych Bloki kodu i zakres zmiennych dowiedzieliśmy się, że zmienne tworzone w metodach muszą być zdefiniowane, zanim zostaną użyte – poniższy przykład nie skompiluje się, ponieważ kompilator w zaznaczonej linii nie wie jeszcze, czym jest "liczba":
public class UzyciePrzedDefinicja {
public static void main(String[] args) {
System.out.println("Liczba = " + liczba);
int liczba = 5;
}
}
Wynik próby kompilacji:
Wróćmy do programu liczącego sumę dwóch liczb:
public class WypiszSume {
public static void main(String[] args) {
wypiszSume(100, 200);
wypiszSume(-5, -20);
wypiszSume(0, 0);
}
public static void wypiszSume(int a, int b) {
System.out.println(a + b);
}
}
Pytanie: dlaczego w tym przypadku kompilacja kończy się sukcesem, a program, po uruchomieniu, wypisuje na ekran sumę podanych liczb, pomimo, że metodę wypiszSume używamy zanim zostanie ona zapisana w kodzie tego programu?
Otóż, metody w klasach nie muszą być w zdefiniowane w kolejności użycia – kompilator analizuje cały plik źródłowy i wie, jakie metody utworzyliśmy. Stąd kompilator nie protestuje widząc linię:
wypiszSume(100, 200);
ponieważ, po analizie całego pliku, wie, że wypiszSume jest metodą z dwoma argumentami, która nie zwraca żadnej wartości.
Wywoływanie metod¶
Co w zasadzie dzieje się, gdy wywołujemy metodę?
Pytanie: jaki będzie wynik działania poniższego programu (co po kolei się zadzieje i jakie komunikaty zobaczymy na ekranie):
import java.util.Scanner;
public class KolejnoscInstrukcji {
public static void main(String[] args) {
System.out.println("Prosze podac liczbe:");
int podanaLiczba = getInt();
System.out.println("Teraz policzymy kwadrat tej liczby.");
double liczbaDoKwadratu = policzKwadrat(podanaLiczba);
System.out.println(
"Kwadrat tej liczby wynosi " + liczbaDoKwadratu
);
}
public static int getInt() {
return new Scanner(System.in).nextInt();
}
public static double policzKwadrat(int liczba) {
return liczba * liczba;
}
}
Wynikiem działania programu będzie:
Komunikaty zostały wyświetlone w tej kolejności, ponieważ gdy wywołujemy metodę, to skaczemy do niej z miejsca, gdzie do tej pory odbywało się wykonywanie programu. W komentarzach poniżej została zapisana kolejność wykonywania instrukcji w powyższym programie:
Strzałki obrazują przepływ działania programu:
- najpierw wypisujemy komunikat z prośbą o podanie liczby (1),
- następnie, gdy pobieramy od użytkownika liczbę (2), skaczemy z metody main do metody getInt (3),
- wracamy do metody main i wypisujemy tekst instrukcją (4),
- ponownie skaczemy z metody main (5) – tym razem do metody policzKwadrat (6),
- po powrocie, wypisujemy wynik obliczenia (7).
Zmienne lokalne¶
W poprzednich rozdziałach korzystaliśmy ze zmiennych w metodzie main, na przykład w programie z trzeciego rozdziału, który liczył pole i obwód koła użyliśmy czterech zmiennych (promienKola, pi, poleKola, oraz obwodKola):
public class ObwodPoleKola {
public static void main(String[] args) {
int promienKola = 8;
double pi = 3.14;
double poleKola = pi * promienKola * promienKola;
double obwodKola = 2 * pi * promienKola;
System.out.println("Pole kola wynosi: " + poleKola);
System.out.println("Obwod kola wynosi: " + obwodKola);
}
}
Napiszmy metodę, która będzie liczyła dla nas pole koła na podstawie jego promienia:
public class PoleKola {
public static void main(String[] args) {
System.out.println(
"Pole kola o promieniu 2 wynosi " + obliczPoleKola(2)
);
}
public static double obliczPoleKola(int promienKola) {
double promienDoKwadratu = promienKola * promienKola;
return 3.14 * promienDoKwadratu;
}
}
Metoda obliczPoleKola:
- przyjmuje jeden argument – promień koła, którego pole chcemy policzyć,
- wylicza kwadrat promienia koła i zapisuje go w zmiennej promienDoKwadratu,
- zwraca wyliczone pole koła przez przemnożenie promienia do kwadratu przez wartość liczby PI.
Pytanie: czy w metodzie main możemy odnieść się do zmiennej promienDoKwadratu, którą zdefiniowaliśmy w metodzie obliczPoleKola?
Spróbujmy:
public class PoleKolaZBledem {
public static void main(String[] args) {
System.out.println(
"Pole kola o promieniu 2 wynosi " + obliczPoleKola(2)
);
System.out.println(
"Promien kola do kwadratu wynosi: " + promienDoKwadratu
);
}
public static double obliczPoleKola(int promienKola) {
double promienDoKwadratu = promienKola * promienKola;
return 3.14 * promienDoKwadratu;
}
}
Próba kompilacji powyższego programu zakończy się następującym błędem:
Kompilator poinformował nas, że nie wie, czym jest "promienDoKwadratu". Wynika to z faktu, że zmienna promienDoKwadratu jest lokalna dla metody obliczPoleKola i jest niedostępna nigdzie indziej w programie poza ciałem tej metody.
Jest to bardzo ważna informacja:
Zmienna promienDoKwadratu dostępna jest jedynie w metodzie obliczPoleKola, od momentu jej (zmiennej) zdefiniowania, do końca metody obliczPoleKola – po zakończeniu działania tej metody, zmienna promienDoKwadratu przestaje istnieć:
public class PoleKolaZBledem {
public static void main(String[] args) {
System.out.println(
"Pole kola o promieniu 2 wynosi " + obliczPoleKola(2)
);
// w metodzie main zmienna promienDoKwadratu nie istnieje,
// wiec kompilator zaprotestuje!
System.out.println(
"Promien kola do kwadratu wynosi: " + promienDoKwadratu
);
}
public static double obliczPoleKola(int promienKola) {
// zmienna promienDoKwadratu dostepna jest od ponizszej linii
double promienDoKwadratu = promienKola * promienKola;
return 3.14 * promienDoKwadratu;
} // metoda sie konczy, zmienna promienDoKwadratu przestaje istniec
}
Kolejne pytanie: czy możemy użyć w main argumentu promienKola? Nie – efekt będzie taki sam, jak przy próbie użycia zmiennej promienDoKwadratu. Obie te zmienne to zmienne lokalne.
Czas życia zmiennych lokalnych¶
W poprzednim rozdziale dowiedzieliśmy się, że zmienne lokalne są dostępne jedynie w metodach, w których zostały utworzone.
Za każdym razem, gdy wywołujemy metodę, zmienne lokalne tworzone są od nowa.
Jaki, w takim razie, będzie wynik działania poniższego programu? Czy zobaczymy na ekranie liczby 10 i 20, czy 10 i 30?
public class CzasZyciaZmiennychLokalnych {
public static void main(String[] args) {
testowaMetoda(10);
testowaMetoda(20);
}
public static void testowaMetoda(int liczba) {
int zmiennaLokalna = 0;
zmiennaLokalna = zmiennaLokalna + liczba;
System.out.println(zmiennaLokalna);
}
}
Na ekranie zobaczymy liczby 10 i 20 – co prawda dodajemy do lokalnej zmiennej o nazwie zmiennaLokalna wartość przesłanego do metody argumentu, ale po zakończeniu metody, zmienna zmiennaLokalna przestaje istnieć i jej wartość przestaje być dostępna – po ponownym uruchomieniu metody testowaMetoda, zmienna zmiennaLokalna tworzona jest po raz kolejny i "nie pamięta", że przy okazji poprzedniego wywołania przypisaliśmy jej wartość 10.
Podsumowanie zakresu i wywoływania metod, zmiennych lokalnych¶
- Metody w klasach nie muszą być zdefiniowane w kolejności użycia – poniższy kod działa poprawnie – metoda wypiszSume nie musi być przed metodą main:
public class WypiszSume { public static void main(String[] args) { wypiszSume(100, 200); wypiszSume(-5, -20); wypiszSume(0, 0); } public static void wypiszSume(int a, int b) { System.out.println(a + b); } } - Gdy wywołujemy metodę, to skaczemy do niej z miejsca, gdzie do tej pory odbywało się wykonywanie programu. Poniższy przykład obrazuje kolejność wykonywania kodu programu, w którym używanych jest kilka metod:

- Zmienne lokalne to zmienne utworzone w ciele metody.
- Zmienne lokalne są lokalne dla metody, w której zostały zdefiniowane i są niedostępne nigdzie indziej w programie poza ciałem tej metody.
- Poniższy przykład obrazuje lokalność zmiennych – kompilacja programu zakończy się błędem, ponieważ w metodzie main próbujemy odnieść się do zmiennej promienDoKwadratu, która jest lokalna (istnieje tylko) w metodzie obliczPoleKola:
public class PoleKolaZBledem { public static void main(String[] args) { System.out.println( "Pole kola o promieniu 2 wynosi " + obliczPoleKola(2) ); System.out.println( "Promien kola do kwadratu wynosi: " + promienDoKwadratu ); } public static double obliczPoleKola(int promienKola) { double promienDoKwadratu = promienKola * promienKola; return 3.14 * promienDoKwadratu; } } - Zmienne lokalne "żyją" w ramach metody, w której zostały utworzone. Za każdym razem, gdy wywołujemy metodę, zmienne lokalne tworzone są od nowa.
Pytania do zakresu i wywoływania metod, zmiennych lokalnych¶
- Czym są zmienne lokalne?
- Czy możemy z metody abc odwołać się do zmiennej lokalnej zdefiniowanej w metodzie xyz?
- Jaki jest zakres życia zmiennych lokalnych?
- Czy poniższy kod jest poprawny i jak go ewentualnie naprawić?
public class ZakresIWywolywanieMetodPytanie1 { public static void main(String[] args) { System.out.println("Wynik: " + kwadrat); int kwadrat = policzKwadrat(10); } public static int policzKwadrat(int liczba) { return liczba * liczba; } } - Jaki będzie wynik działania poniższego programu?
public class ZakresIWywolywanieMetodPytanie2 { public static void main(String[] args) { policzKwadrat(10); System.out.println("Wynik: " + wynik); } public static void policzKwadrat(int liczba) { int wynik = liczba * liczba; } } - Jaki będzie wynik działania poniższego programu – co po kolei zobaczymy na ekranie?
public class ZakresIWywolywanieMetodPytanie3 { public static void main(String[] args) { System.out.println( "Witajcie! Kwadrat 10 to: " + policzKwadrat(10) ); System.out.println("Policzone!"); } public static int policzKwadrat(int liczba) { System.out.println("Liczymy kwadrat liczby " + liczba); return liczba * liczba; } }