Witam. Piszę prosty program o następującej treści:

Utwórz klasę o nazwie Tank() obsłuhgującą operację fill() i empty() wyposażoną w warunek zakończenia wymagający opróżnienia obiektu przed usunieciem. Napisz metode finalize() ktora bedzie sprawdzac stan zbiornika. W metodzie main() sprawdz mozliwe scenariusze używania obiektów klasy Tank.

Napisałem coś takiego:

class Tank {
	
	boolean pelny = false;
	
	void fill() {
		pelny = true;
	}
	
	void empty() {
		pelny = false;
	}
	
	protected void finalize() {
		if(pelny) {
			System.out.println("Blad");
		} else {
			System.out.println("Obiekt usuniety");
		}
	}
}

public class Glowna {

	public static void main(String[] args) {
		
	}
	
}
 

I przykładowo robię coś takiego:

public class Glowna {

	public static void main(String[] args) {

		Tank t = new Tank();
		t.fill();
		t.empty();
		System.gc();;
	}
	
}
 

W konsoli nie otrzymuję niczego. Czyli jak to jest z tym odśmiecaczem, który wywołuję System.gc? Czy nie powinna zostać uruchomiona wtedy ta metoda finalize i wypisać mi na ekranie "Obiekt usuniety"? Wiem, że przy wywołaniu System.gc obiekty mogą zostać usunięte, ale nie muszą. W takim razie po co jest w ogóle ta metoda finalize i to sprawdzanie warunków czy zbiornik będzie pełny czy pusty? Przecież ona nie daje informacji GC czy obiekt ma zostać usunięty jeśli zbiornik = false czy go pozostawić jeśli = true.

Teraz 2 przypadek:

public class Glowna {

	public static void main(String[] args) {

		Tank t = new Tank();
		t.fill();
		t.empty();
		t.finalize();
	}
	
}
 

W odpowiedzi otrzymuję oczywiście "Obiekt został usunięty" i ok. Ale jeśli zrobię np. tak:

public class Glowna {

	public static void main(String[] args) {

		Tank t = new Tank();
		t.fill();
		t.empty();
		t.finalize();
		t.fill();
		t.empty();
	}
	
}
 

Czyli po finalize() odwołam się znów do obiektu t to nie wyskakuje żaden błąd. Tak jakby ten obiekt nadal istniał, a nie został usunięty przez finalize?

I ostatni przypadek

public class Glowna {

	public static void main(String[] args) {

		Tank t = new Tank();
		t.fill();
		t.empty();
		new Tank().fill();
		t.finalize();
		System.gc();
	}
	
}
 

Gdy usunę t.finalize() to nic nie wyskakuje. A przecież System.gc() wymusza to odśmiecanie i new Tank().fill(); nie ma referencji, więc powinien na wyjściu pojawić się komunikat "Błąd" co jednak się nie dzieje. W momencie kiedy dodam t.finalize() to pojawia się już komunikat o błędzie. Czemu to się dzieje w tym przypadku a w poprzednim nie? Przecież t.finalize() wywołuję na rzecz obiektu t a nie żadnych innych.

Ogólnie nie do końca rozumiem bardzo znaczenia tej metody finalize. Wiem, że jest dość rzadko używana, ale jednak chciałbym jakoś ją zrozumieć. Z tego co wnioskuję to tak jakby miała on charakter bardziej informacyjny? Kiedy obiekt jest usuwany przez GC, wtedy wywoływana jest metoda finalize? A przykładowo wywołanie samemu tej metody na rzecz jakiegoś obiektu typu t.finalize() wcale nie musi usunąć obiektu? Służy ona głównie do czyszczenia miejsca w pamięci kiedy pamięć jest alokowana w sposób niestandardowy? Wtedy np. tworzymy takową metodę finalize i w niej np. robimy wszystkie czynności potrzebne do odśmiecania np.

protected void finalize() {

 	  free(coś tam);

}

I dopiero w takim przypadku wywołanie typu jakiśobiekt.finalize() ma jakiś sens? I wtedy rzeczywiście pamięć zostanie wyczyszczona?