Ich bin ziemlich alt. Ich war dort und habe es gesehen und mir oft den Kopf gestoßen.
Ich war auf einer Konferenz in Hursley Park, wo die IBM-Jungs uns erzählten, wie wunderbar diese brandneue Java-Sprache war. Nur jemand fragte ... warum gibt es keinen Destruktor für diese Objekte? Er meinte nicht das, was wir als Destruktor in C ++ kennen, aber es gab auch keinen Finalizer (oder es gab Finalizer, aber sie funktionierten im Grunde nicht). Dies ist weit zurück und wir haben festgestellt, dass Java zu diesem Zeitpunkt eine Art Spielzeugsprache war.
Jetzt haben sie Finalisers in die Sprachspezifikation aufgenommen und Java hat einige Änderungen erfahren.
Natürlich wurde später jeder angewiesen, keine Finalisten auf seine Objekte zu setzen, da dies den GC enorm verlangsamte. (da nicht nur der Heap gesperrt, sondern auch die zu finalisierenden Objekte in einen temporären Bereich verschoben werden mussten, da diese Methoden nicht aufgerufen werden konnten, da der GC die Ausführung der App angehalten hat. Stattdessen wurden sie unmittelbar vor dem nächsten aufgerufen.) GC-Zyklus) (und schlimmer noch, manchmal wurde der Finalizer beim Herunterfahren der App überhaupt nicht aufgerufen. Stellen Sie sich vor, Sie hätten Ihr Datei-Handle niemals geschlossen.)
Dann hatten wir C # und ich erinnere mich an das Diskussionsforum auf MSDN, in dem uns gesagt wurde, wie wunderbar diese neue C # -Sprache war. Jemand fragte, warum es keine deterministische Finalisierung gebe und die MS-Jungs sagten uns, dass wir solche Dinge nicht brauchten, dann sagten sie uns, wir müssten unsere Art, Apps zu entwerfen, ändern, und erklärten uns dann, wie großartig GC sei und wie alle unsere alten Apps seien Quatsch und hat wegen aller Zirkelverweise nie funktioniert. Dann gaben sie dem Druck nach und sagten uns, dass sie dieses IDispose-Muster zu der Spezifikation hinzugefügt hätten, die wir verwenden könnten. Ich dachte, dass es zu diesem Zeitpunkt für uns in C # -Anwendungen so ziemlich wieder manuelle Speicherverwaltung war.
Natürlich stellten die MS-Jungs später fest, dass alles, was sie uns erzählt hatten, ... nun, sie haben IDispose ein bisschen mehr als nur eine Standardschnittstelle gemacht und später die using-Anweisung hinzugefügt. W00t! Sie erkannten, dass die deterministische Finalisierung doch etwas in der Sprache fehlte. Natürlich muss man immer noch daran denken, es überall einzulegen, also ist es immer noch ein bisschen manuell, aber es ist besser.
Warum haben sie es dann getan, wenn sie von Anfang an automatisch eine Semantik nach Verwendungsstil in jeden Gültigkeitsbereichsblock eingefügt haben könnten? Wahrscheinlich Effizienz, aber ich denke gerne, dass sie es einfach nicht gemerkt haben. Genau wie sie irgendwann gemerkt haben, dass Sie in .NET noch intelligente Zeiger benötigen (google SafeHandle), dachten sie, dass der GC wirklich alle Probleme lösen würde. Sie vergaßen, dass ein Objekt mehr als nur Speicher ist und dass GC in erster Linie für die Speicherverwaltung entwickelt wurde. Sie waren in die Idee verwickelt, dass der GC damit umgehen würde, und vergaßen, dass Sie andere Dinge darin ablegen. Ein Objekt ist nicht nur ein Gedächtnisfleck, der keine Rolle spielt, wenn Sie es für eine Weile nicht löschen.
Aber ich denke auch, dass das Fehlen einer Finalisierungsmethode im ursprünglichen Java ein bisschen mehr zu tun hatte - dass die Objekte, die Sie erstellt haben, sich ausschließlich um den Arbeitsspeicher drehten und ob Sie etwas anderes löschen wollten (wie ein DB-Handle oder einen Socket oder was auch immer) ) dann sollten Sie es manuell tun .
Denken Sie daran, Java wurde für eingebettete Umgebungen entwickelt, in denen die Benutzer C-Code mit vielen manuellen Zuweisungen geschrieben haben. Das automatische Freigeben war also kein großes Problem - sie haben es zuvor noch nie getan. Warum sollten Sie es in Java benötigen? Das Problem hatte nichts mit Threads oder Stack / Heap zu tun, sondern war wahrscheinlich nur dazu da, die Speicherzuweisung (und damit die Aufhebung der Zuweisung) etwas zu vereinfachen. Insgesamt ist die try / finally-Anweisung wahrscheinlich ein besserer Ort, um mit Nicht-Speicherressourcen umzugehen.
Also meiner Meinung nach ist die Art und Weise, wie .NET den größten Fehler von Java kopiert, seine größte Schwäche. .NET hätte ein besseres C ++ sein sollen, kein besseres Java.