Baza Wiedzy

JavaTraps 005

W dzisiejszej pułapce poruszymy zagadnienie lokowania zmiennych w pamięci, ich porównywania i tego co tak naprawdę zmieniamy przekazując argumenty metodom. Dodatkowym zagadnieniem są referencje finalne.

Warto się nad tym zastanowić, ponieważ zarówno początkujący jak i nieco bardziej doświadczeni programiści często mogą wpaść w problemy. Błędy spowodowane z zagadnieniem, które poruszamy może być powodem błędów bardzo trudnych do wykrycia w przypadku skomplikowanej hierarchii klas i tysiącach linii kodu odnalezienie źródła komplikacji zajmie nam wiele godzin.

Kurs Programowania Java

Poniższy kod przedstawia dwie klasy. Pierwsza z nich posłuży nam do utworzenia obiektu przechowującego jedną wartość typu int. W drugiej przetestujemy różne działania z nią związane.

public class Zmienna {
	public Zmienna(int x) {
		this.x = x;
	}

	public int x;
}
public class Test {

	static void metoda1(Zmienna z) {
		z.x = -1;
		z = null;
	}

	static void metoda2(final Zmienna z) {
		z.x = -2;
	}

	public static void main(String[] args) {
		Zmienna a = new Zmienna(1);
		final Zmienna b = new Zmienna(2);

		//instrukcja 1
		metoda1(a);
		System.out.print(a.x + " ");
		//instrukcja 2
		metoda1(b);
		System.out.print(b.x + " ");

		Zmienna c = new Zmienna(1);
		final Zmienna d = new Zmienna(2);

		//instrukcja 3
		metoda2(c);
		System.out.print(c.x + " ");
		//instrukcja 4
		metoda2(d);
		System.out.print(d.x + " ");
	}
}

Pytanie jak zwykle: co się stanie po wykonaniu instrukcji 1,2,3,4?

a) NullPointerException ...

b) 1 2 1 2

c) -1 -1 -1 -1

d) -1 -1 -2 -2

e) Inna odpowiedź

 

 

 

 

 

Odpowiedź

public class Zmienna {
	public Zmienna(int x) {
		this.x = x;
	}

	public int x;
}
public class Test {

	static void metoda1(Zmienna z) {
		z.x = -1;
		z = null;
	}

	static void metoda2(final Zmienna z) {
		z.x = -2;
	}

	public static void main(String[] args) {
		Zmienna a = new Zmienna(1);
		final Zmienna b = new Zmienna(2);

		//instrukcja 1
		metoda1(a);
		System.out.print(a.x + " ");
		//instrukcja 2
		metoda1(b);
		System.out.print(b.x + " ");

		Zmienna c = new Zmienna(1);
		final Zmienna d = new Zmienna(2);

		//instrukcja 3
		metoda2(c);
		System.out.print(c.x + " ");
		//instrukcja 4
		metoda2(d);
		System.out.print(d.x + " ");
	}
}

W zadaniu tym mogą wystąpić problemy w kilku miejscach. Po pierwsze, co tak naprawdę zmodyfikuje metoda 1? Przyjmuje ona jako parametr obiekt typu Zmienna. Jej pole x jest publiczne więc jego modyfikacja jest jak najbardziej poprawna. Co jednak w przypadku, gdy przekazujemy do tej metody zmienną (stałą) finalną? Przecież to co pierwsze przychodzi do głowy - nie można tego obiektu zmodyfikować!

Nic bardziej mylnego. W Javie istnieją finalne referencje, a nie finalne obiekty! Nie można więc do referencji a przypisać nowego, lub innego już istniejącego obiektu. Bez problemu można jednak zmieniać widoczne pola, które nie są oznaczone jako final.

Druga sprawa to przypisanie zmiennej null do parametru metody. Oczywiście referencje zmiennych a, ani b nie zostaną zmienione. Dzieje się tak dlatego, że w Javie parametry są przekazywane przez wartość (pass by value), a nie przez referencję. Tak więc referencja z wskazuje na ten sam obiekt, ale nie jest tą samą referencją co zmienna a i b.

Metoda 2 nie przynosi już więcej pułapek.

Wynikiem jest więc odpowiedź d) -1 -1 -2 -2

Zapisz się do newslettera

Otrzymuj nasz Newsletter z przykładowymi pytaniami rekrutacyjnymi, wyzwaniami programistycznymi i nowościami ze świata Javy, a także informacje o nowych kursach i promocjach.

Traktujemy Twoją prywatność poważnie. Nikomu nie udostępniamy Twojego maila no i zawsze możesz się wypisać.

Komentarze do artykułu

Wyłączyliśmy możliwość dodawania komentarzy. Poniżej znajdziesz archiwalne wpisy z czasów gdy strona była jeszcze hobbystycznym blogiem. Zapraszamy natomiast do zadawnia pytań i dyskusji na naszej grupe na facebooku.

Szkolenie Java WrocławJavaStart na Youtube