4.4.1 | Finalisierung von Objekten |
Als Ersatz für Destruktoren kann eine Klasse in Java die von Object geerbte Methode finalize() überschreiben, in der Abschlussaktionen implementiert werden können. Diese Methode wird auch Finalisierer (Finalizer) genannt. finalize() wird automatisch vom Garbage Collector aufgerufen, bevor das Objekt entfernt wird.
Eine flexiblere Möglichkeit zur Implementierung von Abschlussaktionen bieten die Referenzklassen oder die Shutdown-Routinen.
Die Klasse java.io.FileInputStream ist ein Beispiel aus der Standardbibliothek, das von der Finalisierung Gebrauch macht. Mit FileInputStream können Daten aus einer Datei gelesen werden. Sie muss vor der Entfernung des Objekts noch eine Datei schließen und überschreibt hierzu finalize() entsprechend:protected void finalize() throws IOException { if (fd != null) { if (fd != fd.in) { close(); } }finalize() wird standardmäßig mit der Zugriffsklasse protected vereinbart.
Hier noch einmal der genaue Ablauf:Bezüglich der Finalisierung gelten folgende Regeln:
- Zunächst prüft der Garbage Collector, ob es noch Verweise auf das Objekt gibt. Wenn es keine Verweise mehr gibt, hängt das weitere Vorgehen davon ab, ob die zugehörige Klasse einen Finalisierer besitzt. Wenn sie keinen Finalisierer besitzt, wird das Objekt entfernt, und der Speicher steht sofort wieder zur weiteren Nutzung bereit.
- Falls das Objekt dagegen über einen Finalisierer verfügt, wird er aufgerufen.
- Nachdem finalize() ausgeführt wurde, wird noch einmal geprüft, ob es keine Verweise auf das Exemplar mehr gibt, bevor der Speicher freigegeben wird. Diese Überprüfung ist notwendig, da prinzipiell im Finalisierer wieder ein Verweis auf das Exemplar erzeugt werden kann. Wenn die Prüfung ergibt, dass kein neuer Verweis erzeugt wurde, dann wird der Speicher freigegeben. Wurde dagegen ein neuer Verweis auf das Exemplar angelegt, wird das Objekt sofort entfernt, wenn es zu einem späteren Zeitpunkt keine Verweise mehr gibt. Der Finalisierer wird hierbei kein zweites Mal aufgerufen.
- Es besteht keine Garantie dafür, dass finalize() aufgerufen wird. Möglicherweise wird der Garbage Collector während der Laufzeit des Interpreters gar nicht aufgerufen, so dass noch belegte Ressourcen vom Betriebssystem freigegeben werden. Für Abschlussaktionen, die garantiert ausgeführt werden sollen, muss auf Referenzklassen oder Shutdown-Routinen zurückgegriffen werden.
- Der Finalisierer eines Exemplars wird höchstens einmal aufgerufen.
- Falls bei der Ausführung von finalize() eine Exception auftritt, die nicht in der Methode selbst abgefangen wird, dann wird die Ausführung des Programms nicht abgebrochen, sondern die Exception wird ignoriert.
- Da der Garbage Collector asynchron läuft, können keine Annahmen über den Aufrufzeitpunkt von finalize() gemacht werden.
- Es können keine Annahmen darüber gemacht werden, in welcher Reihenfolge Objekte entfernt werden.
Seit der Version 1.1 besteht die Möglichkeit, mit dem Aufruf
System.runFinalization();noch ausstehende Finalisierungen sofort zu starten. Alternativ kann mitSystem.runFinalizersOnExit(true);die Ausführung ausstehender finalize()-Methoden am Ende der Laufzeit der Virtual Machine erzwungen werden.