Nach meiner Erfahrung gibt es nur einen Grund für das Überschreiben Object.finalize()
, aber es ist ein sehr guter Grund :
Um Fehlerprotokollierungscode zu platzieren, finalize()
der Sie benachrichtigt, wenn Sie das Aufrufen vergessen close()
.
Die statische Analyse kann nur Auslassungen in Szenarien mit geringer Auslastung erkennen, und die Compiler-Warnungen, die in einer anderen Antwort erwähnt werden, enthalten eine so vereinfachte Sicht der Dinge, dass Sie sie tatsächlich deaktivieren müssen, um alles zu tun, was nicht trivial ist. (Ich habe weit mehr Warnungen aktiviert als jeder andere Programmierer, den ich kenne oder von dem ich je gehört habe, aber ich habe keine dummen Warnungen aktiviert.)
Die Finalisierung scheint ein guter Mechanismus zu sein, um sicherzustellen, dass die Ressourcen nicht ungenutzt bleiben. Die meisten Menschen sehen dies jedoch völlig falsch: Sie sehen darin einen alternativen Fallback-Mechanismus, eine "zweite Chance", die die Ressourcen automatisch schützt Tag durch Entsorgung der Ressourcen, die sie vergessen haben. Das ist absolut falsch . Es muss nur eine Möglichkeit geben, etwas zu tun: Entweder schließen Sie immer alles, oder die Finalisierung schließt immer alles. Da die Finalisierung jedoch unzuverlässig ist, kann es nicht die Finalisierung sein.
Es gibt also dieses Schema, das ich Mandatory Disposal nenne , und das besagt, dass der Programmierer dafür verantwortlich ist, immer explizit alles zu schließen, wasCloseable
oder implementiert AutoCloseable
. (Die Anweisung "try-with-resources" gilt immer noch als explizites Schließen.) Natürlich kann der Programmierer dies vergessen. Hier kommt also die Finalisierung ins Spiel, aber nicht als magische Fee, die die Dinge am Ende auf magische Weise richtig macht: Wenn die Finalisierung entdeckt wird das close()
wurde nicht aufgerufen, tut es nichtversuchen, es aufzurufen, gerade weil es (mit mathematischer Sicherheit) Horden von n00b-Programmierern geben wird, die sich darauf verlassen werden, dass es die Arbeit erledigt, für die sie zu faul oder zu abwesend waren. Wenn Finalization bei der obligatorischen Entsorgung feststellt, dass diese Funktion close()
nicht aufgerufen wurde, wird eine leuchtend rote Fehlermeldung protokolliert, die dem Programmierer mit großen, fetten Großbuchstaben mitteilt, er solle sein Problem beheben.
Als zusätzlichen Vorteil geht das Gerücht aus, dass "die JVM eine triviale finalize () -Methode ignorieren wird (z. B. eine, die nur zurückkehrt, ohne etwas zu tun, wie es in der Object-Klasse definiert ist)", sodass Sie bei obligatorischer Entsorgung jegliche Finalisierung vermeiden können Overhead in Ihrem gesamten System ( Informationen darüber, wie schrecklich dieser Overhead ist, finden Sie in der Antwort von alip ), indem Sie Ihre finalize()
Methode wie folgt codieren :
@Override
protected void finalize() throws Throwable
{
if( Global.DEBUG && !closed )
{
Log.Error( "FORGOT TO CLOSE THIS!" );
}
//super.finalize(); see alip's comment on why this should not be invoked.
}
Die Idee dahinter ist, dass Global.DEBUG
es sich um eine static final
Variable handelt, deren Wert zum Kompilierungszeitpunkt bekannt ist. Wenn dies false
der Fall ist, gibt der Compiler überhaupt keinen Code für die gesamte if
Anweisung aus, wodurch dies zu einem trivialen (leeren) Finalizer wird, der wiederum bedeutet, dass Ihre Klasse so behandelt wird, als hätte sie keinen Finalizer. (In C # würde dies mit einem netten #if DEBUG
Block geschehen , aber was können wir tun, das ist Java, wo wir anscheinend Einfachheit im Code mit zusätzlichem Overhead im Gehirn bezahlen.)
Weitere Informationen zur Entsorgungspflicht mit zusätzlichen Erläuterungen zur Entsorgung von Ressourcen in dot Net finden Sie hier: michael.gr: Entsorgungspflicht vs.
finalize()
ein bisschen durcheinander. Wenn Sie es jemals implementieren, stellen Sie sicher, dass es in Bezug auf alle anderen Methoden für dasselbe Objekt threadsicher ist.