Czy istnieje Java Destruktor?


594

Czy istnieje Java Destruktor? Wydaje mi się, że nie jestem w stanie znaleźć żadnej dokumentacji na ten temat. Jeśli nie, to jak mogę osiągnąć ten sam efekt?

Aby uściślić moje pytanie, piszę aplikację, która zajmuje się danymi, a specyfikacja mówi, że powinien istnieć przycisk „reset”, który przywróci aplikację do pierwotnego stanu, w którym właśnie została uruchomiona. Jednak wszystkie dane muszą być „aktywne”, chyba że aplikacja zostanie zamknięta lub przycisk resetowania nie zostanie naciśnięty.

Będąc zwykle programistą C / C ++, pomyślałem, że byłoby to trywialne do wdrożenia. (I dlatego planowałem go zaimplementować na końcu.) Skonstruowałem swój program tak, aby wszystkie obiekty, które można zresetować, były w tej samej klasie, dzięki czemu mogłem po prostu zniszczyć wszystkie żywe obiekty po naciśnięciu przycisku resetowania.

Zastanawiałem się, czy wszystko, co zrobiłem, to po prostu odsunąć dane i poczekać, aż zbieracz śmieci je zbierze, czy nie byłoby przecieku pamięci, gdyby mój użytkownik wielokrotnie wprowadzał dane i naciskał przycisk resetowania? Myślałem również, że ponieważ Java jest dość dojrzała jako język, powinien istnieć sposób, aby temu zapobiec lub z wdziękiem się tym zająć.


7
Wyciek pamięci występuje tylko wtedy, gdy przechowujesz odniesienia do niepotrzebnych obiektów. tzn. w twoim programie jest błąd. GC będzie działać zgodnie z potrzebami (czasem wcześniej)
Peter Lawrey

17
Maszyna wirtualna nie uruchomi GC wystarczająco szybko, jeśli szybko przetwarzasz dane przez obiekty. Pomysł, że GC może zawsze nadążyć lub podejmować właściwe decyzje, jest błędem.
Kieveli

1
@Kieveli Czy JVM nie uruchomi GC przed wystąpieniem błędu?
WVrock,

4
Tak, byłoby miło, gdyby istniał destruktor dla Javy, który zniszczyłby go raz na zawsze.
Tomáš Zato - Przywróć Monikę

Odpowiedzi:


526

Ponieważ Java jest językiem wyrzucania elementów bezużytecznych, nie można przewidzieć, kiedy (a nawet jeśli) obiekt zostanie zniszczony. Dlatego nie ma bezpośredniego odpowiednika destruktora.

Istnieje dziedziczna metoda o nazwie finalize, ale jest ona wywoływana całkowicie według uznania śmieciarza. Tak więc dla klas, które muszą jawnie posprzątać, konwencja polega na zdefiniowaniu metody close i użyciu finalizacji tylko do sprawdzania poczytalności (tj. Jeśli close nie został wywołany, zrób to teraz i zaloguj błąd).

Pojawiło się niedawno pytanie, które doprowadziło do dogłębnej dyskusji na temat finalizacji , aby w razie potrzeby zapewnić większą głębię ...


5
Czy „close ()” w tym kontekście odnosi się do metody w java.lang.Autocloseable?
Sridhar Sarnobat

21
Nie, AutoCloseable został wprowadzony w Javie 7, ale konwencja „close ()” istnieje już znacznie dłużej.
Jon Onstott

dlaczego nie możesz przewidzieć, kiedy (a nawet jeśli) obiekt zostanie zniszczony. jaki przybliżony inny sposób to przewidzieć?
dctremblay,

Niszczenie obiektów @dctremblay odbywa się przez moduł czyszczenia pamięci, a moduł czyszczenia pamięci może nigdy nie działać w czasie użytkowania aplikacji.
Piro mówi Przywróć Monikę

4
Zwróć uwagę, że finalizemetoda została wycofana w Javie 9.
Lii

124

Spójrz na try-with-resources . Na przykład:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  System.out.println(br.readLine());
} catch (Exception e) {
  ...
} finally {
  ...
}

Tutaj zasób, który nie jest już potrzebny, jest zwalniany w BufferedReader.close()metodzie. Możesz stworzyć własną klasę, która implementuje ją AutoCloseablei używa w podobny sposób.

To stwierdzenie jest bardziej ograniczone niż finalizew zakresie struktury kodu, ale jednocześnie ułatwia zrozumienie i utrzymanie kodu. Ponadto nie ma gwarancji, że finalizemetoda zostanie w ogóle wywołana w czasie trwania aplikacji.


12
Dziwi mnie, że ma tak mało głosów. To jest rzeczywista odpowiedź.
nurettin

20
Nie zgadzam się, że to jest prawdziwa odpowiedź. Jeśli instancja ma zasób, który obsługuje przez dłuższy czas, w wielu wywołaniach metod, wówczas próba z zasobami nie pomoże. O ile nie jest możliwe zamknięcie i ponowne otwarcie wspomnianego zasobu z częstotliwością, o której wspomniane metody są wywoływane - to nie jest ogólny fakt.
Eric,

14
Rzeczywiście, nie jest to rzeczywista odpowiedź. Niemożliwe jest użycie tej struktury do zarządzania zniszczeniem obiektu, chyba że konstrukcja i użytkowanie obiektu jest całkowicie otoczone przez tryi finallysłuży do wymuszenia wywołania obj.finalize(). I nawet ta konfiguracja nie rozwiązuje problemu związanego z OP: niszczenie obiektów w trakcie programu uruchamiane przyciskiem „reset”.
7yl4r

1
Inni użytkownicy pokazali, że dzieje się to w punkcie wejścia aplikacji. Zdefiniuj swoją zmienną globalnie. Zainicjuj go w funkcji wprowadzania za pomocą try. Deinitialize na końcu (kiedy twoja aplikacja zostanie zamknięta). Jest to całkowicie możliwe.
TamusJRoyce,

1
@Nurettin Java 7 był dostępny tylko przez 3 miesiące, kiedy pytanie zostało zadane, jeśli to pomaga lepiej to zrozumieć.
corsiKa

110

Nie, nie ma tutaj niszczycieli. Powodem jest to, że wszystkie obiekty Java są przydzielane do sterty i usuwane śmieci. Bez wyraźnego zwolnienia (tj. Operatora usuwania C ++) nie ma rozsądnego sposobu na implementację prawdziwych destruktorów.

Java obsługuje finalizatory, ale mają one być używane tylko jako zabezpieczenie dla obiektów trzymających uchwyt do zasobów rodzimych, takich jak gniazda, uchwyty plików, uchwyty okien itp. Gdy moduł odśmiecający zbiera obiekt bez finalizatora, po prostu zaznacza pamięć region jako wolny i to wszystko. Gdy obiekt ma finalizator, najpierw jest kopiowany do tymczasowej lokalizacji (pamiętaj, że zbieramy śmieci), a następnie umieszczany jest w kolejce oczekującej na finalizację, a następnie wątek finalizatora odpytuje kolejkę z bardzo niskim priorytetem i uruchamia finalizator.

Po zamknięciu aplikacji JVM zatrzymuje się, nie czekając na sfinalizowanie obiektów oczekujących, więc praktycznie nie ma gwarancji, że finalizatory kiedykolwiek będą działać.


4
Dziękujemy za wspomnienie o rodzimych zasobach - jest to jeden z obszarów, w którym przydatna jest metoda „podobna do destruktora”.
Nathan Osman,

tak, mam teraz ten sam problem z uwolnieniem zasobów / uchwytów przydzielonych przez rodzime wywołania do C ++.
nikk

@ddimitrov, teoretycznie czy Java mogłaby wdrożyć jawne zwolnienie? Czy jest to logiczna sprzeczność?
mils

1
@mils naiwnie wdrażając jawne zwolnienie, albo złamałoby założenie Javy, że wszelkie odniesienia wskazują na obiekt aktywny. Możesz iterować wszystkie wskaźniki i niwelować aliasy, ale jest to droższe niż GC. Możesz też spróbować użyć systemu liniowego (patrz „własność” w Rust), ale jest to poważna zmiana języka. Istnieją również inne opcje (patrz pamięć o zasięgu JavaRT itp.), Ale ogólnie jawne zwolnienie nie pasuje dobrze do języka Java.
ddimitrov

31

Zastosowanie finalize () unikać stosowania metod . Nie są niezawodnym mechanizmem czyszczenia zasobów i możliwe jest spowodowanie problemów w śmieciarzu poprzez ich nadużywanie.

Jeśli potrzebujesz wywołania dealokacji w swoim obiekcie, powiedzmy, aby zwolnić zasoby, użyj jawnego wywołania metody. Konwencję tę można zobaczyć w istniejących interfejsach API (np. Closeable , Graphics.dispose () , Widget.dispose () ) i zwykle wywoływana jest przez try / wreszcie.

Resource r = new Resource();
try {
    //work
} finally {
    r.dispose();
}

Próby użycia rozmieszczonego obiektu powinny wygenerować wyjątek czasu wykonywania (patrz wyjątek IllegalStateException ).


EDYTOWAĆ:

Zastanawiałem się, czy wszystko, co zrobiłem, to po prostu wyrejestrować dane i poczekać, aż zbieracz śmieci je zbierze, czy nie byłoby przecieku pamięci, gdyby mój użytkownik wielokrotnie wprowadzał dane i naciskał przycisk resetowania?

Zasadniczo wszystko, co musisz zrobić, to wyłuskać obiekty - przynajmniej tak powinien działać. Jeśli martwisz się wyrzucaniem elementów bezużytecznych, sprawdź Java SE 6 HotSpot [tm] Virtual Tuning Garbage Collection Tuning (lub dokument równoważny dla twojej wersji JVM).


1
To nie oznacza dereferencji. Nie jest to „ustawianie ostatniego odwołania do obiektu na zero”, ale raczej pobieranie (odczytywanie) wartości z odwołania, aby można było użyć go do kolejnych operacji.

1
Czy try..finally wciąż jest prawidłowym i zalecanym podejściem? Załóżmy, że poprzednio wywoływałem metodę rodzimą w finalize (), czy mogę przenieść wywołanie do klauzuli ostatecznie? class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
aashima

r nie byłby ograniczony do ostatniego bloku. Dlatego nie możesz w tym momencie nazywać zniszczeniem. Teraz, jeśli poprawisz zakres, aby utworzyć obiekt przed blokiem try, skończyłbyś się brzydką sprawą „przed próbą z zasobami”.
userAsh

21

Po wydaniu Java 1.7 masz teraz dodatkową opcję korzystania z try-with-resourcesbloku. Na przykład,

public class Closeable implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("closing..."); 
    }
    public static void main(String[] args) {
        try (Closeable c = new Closeable()) {
            System.out.println("trying..."); 
            throw new Exception("throwing..."); 
        }
        catch (Exception e) {
            System.out.println("catching..."); 
        }
        finally {
            System.out.println("finalizing..."); 
        } 
    }
}

Jeśli wykonasz tę klasę, c.close()zostanie wykonana, gdy tryblok zostanie opuszczony, a przed wykonaniem bloków catchi finally. W przeciwieństwie do tej finalize()metody, close()gwarantuje się, że zostanie wykonana. Jednak nie ma potrzeby wykonywania go jawnie w finallyklauzuli.


co jeśli nie użyliśmy bloku try-with-resources? Myślę, że możemy wywołać close w finalize () tylko po to, aby upewnić się, że close został wywołany.
shintoZ

3
@shintoZ, jak czytam w powyższych odpowiedziach, nie ma gwarancji finalize()wykonania
Asif Mushtaq,

14

W pełni zgadzam się na inne odpowiedzi, mówiąc, że nie polegam na wykonaniu finalizacji.

Oprócz bloków try-catch-Wreszcie możesz użyć Runtime # addShutdownHook (wprowadzonego w Javie 1.3), aby wykonać końcowe porządki w twoim programie.

To nie to samo, co destruktory , ale można zaimplementować hak zamykania, w którym zarejestrowane są obiekty nasłuchiwania, na których można wywoływać metody czyszczenia (zamykanie trwałych połączeń z bazą danych, usuwanie blokad plików itp.) - rzeczy, które normalnie można by wykonać w niszczyciele . Znowu - nie jest to zamiennik dla destruktorów, ale w niektórych przypadkach możesz w ten sposób podejść do pożądanej funkcjonalności.

Zaletą tego jest luźne powiązanie zachowania dekonstrukcyjnego z resztą programu.


addShutdownHook został najwyraźniej wprowadzony w Javie 1.3. W każdym razie jest dostępny dla mnie w wersji 1.5. :) Zobacz to: stackoverflow.com/questions/727151/…
skiphoppy

1
Do twojej wiadomości, według mojego doświadczenia, haki zamykające nie będą wywoływane, jeśli użyjesz czerwonego przycisku „zakończ” w Eclipse - cała JVM jest natychmiast niszczona, haki zamykające nie są wdzięcznie wywoływane. Oznacza to, że możesz zaobserwować inne zachowanie podczas programowania i produkcji, jeśli rozwijasz się za pomocą Eclipse
Hamy,

11

Nie, java.lang.Object#finalize jest najbliżej.

Jednak kiedy jest wywoływane (i jeśli), nie jest gwarantowane.
Widzieć:java.lang.Runtime#runFinalizersOnExit(boolean)


5
Metoda, która może zostać wywołana lub nie, jest zasadniczo bezużyteczna w mojej książce. Lepiej byłoby nie zanieczyszczać języka niepotrzebną specjalną metodą, która w najlepszym razie daje fałszywe poczucie bezpieczeństwa. Nigdy nie zrozumiem, dlaczego twórcy języka Java pomyśleli, że finalizacja jest dobrym pomysłem.
antred

@antred Twórcy języka Java zgadzają się . Wydaje mi się, że dla niektórych z nich po raz pierwszy zaprojektowali język programowania i środowisko wykonawcze z odśmiecaniem. Mniej zrozumiałe jest, dlaczego ten inny język zarządzany skopiował tę koncepcję w tym samym czasie, kiedy już zrozumiano, że ta koncepcja jest złym pomysłem.
Holger

7

Po pierwsze, zauważ, że skoro Java jest gromadzona na śmietnikach, rzadko trzeba robić cokolwiek z niszczeniem obiektów. Po pierwsze dlatego, że zwykle nie masz żadnych zarządzanych zasobów do zwolnienia, a po drugie dlatego, że nie możesz przewidzieć, kiedy to nastąpi, a więc nie jest to odpowiednie dla rzeczy, które musisz zdarzyć, „gdy tylko nikt już nie będzie używać mojego obiektu „.

Możesz zostać powiadomiony po zniszczeniu obiektu za pomocą java.lang.ref.PhantomReference (w rzeczywistości stwierdzenie, że został zniszczony, może być nieco niedokładny, ale jeśli odwołanie fantomowe do niego jest w kolejce, nie jest już możliwe do odzyskania, co zwykle wynosi to samo). Typowym zastosowaniem jest:

  • Rozdziel zasoby w klasie, które należy zniszczyć, na inny obiekt pomocnika (zwróć uwagę, że jeśli wszystko, co robisz, to zamknięcie połączenia, co jest częstym przypadkiem, nie musisz pisać nowej klasy: połączenie, które zostanie zamknięte, byłoby w tym przypadku „obiektem pomocniczym”).
  • Kiedy tworzysz swój główny obiekt, utwórz również PhantomOdniesienie do niego. Niech to odniesie się do nowego obiektu pomocnika lub skonfiguruj mapę z obiektów PhantomReference do odpowiadających im obiektów pomocnika.
  • Po zebraniu głównego obiektu PhantomReference jest umieszczany w kolejce (a raczej może być w kolejce - podobnie jak finalizatory nie ma gwarancji, że kiedykolwiek będzie, na przykład, jeśli VM zakończy działanie, to nie będzie czekać). Upewnij się, że przetwarzasz jego kolejkę (w specjalnym wątku lub od czasu do czasu). Z powodu twardego odwołania do obiektu pomocnika obiekt pomocnika nie został jeszcze zebrany. Zrób więc wszystko, co chcesz na obiekcie pomocnika, a następnie odrzuć PhantomReference, a pomocnik w końcu również zostanie zebrany.

Istnieje również finalize (), który wygląda jak destruktor, ale nie zachowuje się jak jeden. Zwykle nie jest to dobra opcja.


Dlaczego PhantomReference zamiast WeakReference?
uckelman

2
@uckelman: jeśli wszystko, czego potrzebujesz, to powiadomienie, to PhantomReference wykonuje zadanie, jest to właściwie to, do czego jest przeznaczony. Dodatkowa semantyka WeakReference nie jest tutaj potrzebna, aw momencie, w którym twoja ReferenceQueue jest powiadamiana, nie możesz już odzyskać obiektu przez WeakReference, więc jedynym powodem, aby go użyć, jest oszczędzanie sobie konieczności pamiętania, że ​​istnieje PhantomReference. Każda dodatkowa praca wykonywana przez WeakReference jest prawdopodobnie znikoma, ale po co się tym przejmować?
Steve Jessop,

Dziękujemy za podpowiedź w PhantomReference. To nie jest idealne, ale wciąż lepsze niż nic.
foo

@ SteveJessop, jak myślisz, jaka „dodatkowa praca” ma słabe odniesienie w porównaniu do fantomowego odniesienia?
Holger

6

The finalize()Funkcja jest destruktor.

Nie należy go jednak normalnie używać, ponieważ wywoływany jest po GC i nie można powiedzieć, kiedy to nastąpi (jeśli w ogóle).

Co więcej, potrzeba więcej niż jednego GC, aby cofnąć przydział obiektów, które mają finalize() .

Powinieneś spróbować posprzątać w logicznych miejscach swojego kodu za pomocą try{...} finally{...}instrukcji!


5

Zgadzam się z większością odpowiedzi.

Nie powinieneś w pełni polegać na którymkolwiek finalizelubShutdownHook

sfinalizować

  1. JVM nie gwarantuje, kiedy ta finalize()metoda zostanie wywołana.

  2. finalize()jest wywoływany tylko raz przez wątek GC. Jeśli obiekt ożywi się po sfinalizowaniu metody, finalizenie zostanie ponownie wywołany.

  3. W twojej aplikacji możesz mieć jakieś obiekty aktywne, na których nigdy nie wywoływane jest czyszczenie pamięci.

  4. Wszystko, Exceptionco zostanie wyrzucone metodą finalizującą, jest ignorowane przez wątek GC

  5. System.runFinalization(true)i Runtime.getRuntime().runFinalization(true)metody zwiększają prawdopodobieństwo wywołania finalize()metody, ale teraz te dwie metody są przestarzałe. Te metody są bardzo niebezpieczne z powodu braku bezpieczeństwa wątków i możliwego impasu.

shutdownHooks

public void addShutdownHook(Thread hook)

Rejestruje nowy hak zamykania maszyny wirtualnej.

Maszyna wirtualna Java wyłącza się w odpowiedzi na dwa rodzaje zdarzeń:

  1. Program kończy się normalnie, gdy kończy się ostatni wątek niebędący demonem lub gdy kończy działanie (równoważnie, System.exit wywoływana jest metoda ) lub
  2. Maszyna wirtualna zostaje zakończona w odpowiedzi na przerwanie przez użytkownika, takie jak wpisanie ^ C lub zdarzenie systemowe, takie jak wylogowanie użytkownika lub zamknięcie systemu.
  3. Hak zamykający to po prostu zainicjowany, ale nie rozpoczęty wątek. Gdy maszyna wirtualna rozpocznie sekwencję zamykania, uruchomi wszystkie zarejestrowane przechwytywania zamykania w nieokreślonej kolejności i pozwoli na ich jednoczesne działanie. Po zakończeniu wszystkich przechwyceń uruchomi wszystkie nieproszone finalizatory, jeśli włączono finalizację przy wyjściu.
  4. Wreszcie maszyna wirtualna się zatrzyma. Zauważ, że wątki demonów będą nadal działać podczas sekwencji zamykania, podobnie jak wątki nieemonowe, jeśli zamknięcie zostało zainicjowane przez wywołanie metody wyjścia.
  5. Haki zamykające powinny również szybko zakończyć pracę. Gdy program wywołuje zakończenie, oczekuje się, że maszyna wirtualna natychmiast się zamknie i zakończy działanie.

    Ale cytowała to nawet dokumentacja Oracle

W rzadkich przypadkach maszyna wirtualna może przerwać, to znaczy przestać działać bez wyłączania się

Dzieje się tak, gdy maszyna wirtualna zostaje zakończona zewnętrznie, na przykład z SIGKILLsygnałem w systemie Unix lub TerminateProcesswywołaniem w systemie Microsoft Windows. Maszyna wirtualna może również przerwać działanie, jeśli natywna metoda nie zadziała, na przykład poprzez uszkodzenie wewnętrznych struktur danych lub próbę uzyskania dostępu do nieistniejącej pamięci. Jeśli maszyna wirtualna przerwie działanie, nie można zagwarantować, czy uruchomione zostaną jakieś haki zamykania.

Wniosek : użyj try{} catch{} finally{}bloków odpowiednio i uwolnij krytyczne zasoby w finally(}bloku. Podczas uwalniania zasobów w finally{}bloku łap Exceptioni Throwable.


4

Jeśli martwisz się tylko pamięcią, nie rób tego. Ufaj GC, że wykonuje przyzwoitą robotę. Rzeczywiście widziałem coś w tym, że jest tak wydajne, że lepszym rozwiązaniem może być tworzenie stosów drobnych obiektów niż wykorzystywanie dużych tablic w niektórych przypadkach.


3

Być może możesz użyć bloku try ... wreszcie, aby sfinalizować obiekt w przepływie sterowania, w którym używasz tego obiektu. Oczywiście nie dzieje się to automatycznie, ale zniszczenie w C ++ też nie. Często widzisz zamknięcie zasobów w ostatnim bloku.


1
To poprawna odpowiedź, gdy dany zasób ma jednego właściciela i nigdy nie ma odniesień do niego „skradzionych” przez inny kod.
Steve Jessop,

3

W Lombok znajduje się adnotacja @Cleanup, która w większości przypomina destruktory C ++:

@Cleanup
ResourceClass resource = new ResourceClass();

Podczas przetwarzania (w czasie kompilacji) Lombok wstawia odpowiedni try-finallyblok, aby resource.close()był wywoływany, gdy wykonanie wychodzi poza zakres zmiennej. Możesz także wyraźnie określić inną metodę zwolnienia zasobu, np . resource.dispose():

@Cleanup("dispose")
ResourceClass resource = new ResourceClass();

2
Zaletą, którą widzę, jest to, że będzie mniej zagnieżdżania (co może być znaczące, jeśli masz wiele obiektów, które wymagają „zniszczenia”).
Alexey

Blok „spróbuj z zasobami” może mieć wiele zasobów za jednym razem
Alexander - Przywróć Monikę

1
Ale nie może zawierać instrukcji między nimi.
Alexey

Targi. Przypuszczam, że wtedy zaleceniem jest, aby preferować try-with-resource, nawet dla wielu zasobów, chyba że potrzebna była instrukcja między nimi, która zmusiła cię do tworzenia nowych bloków try-with-resource (zwiększenie zagnieżdżania), a następnie użyj@Cleanup
Alexander - Przywróć Monica

2

Najbliższym odpowiednikiem destruktora w Javie jest metoda finalize () . Dużą różnicą w stosunku do tradycyjnego destruktora jest to, że nie możesz być pewien, kiedy zostanie on wywołany, ponieważ jest to obowiązkiem śmieciarza. Zdecydowanie zalecam uważne przeczytanie tego przed użyciem, ponieważ typowe wzorce RAIA dla uchwytów plików i tak dalej nie będą działać niezawodnie z finalize ().


2

Wiele świetnych odpowiedzi tutaj, ale jest kilka dodatkowych informacji na temat tego, dlaczego należy unikać używania finalize () .

Jeśli JVM zakończy działanie z powodu System.exit()lub Runtime.getRuntime().exit(), finalizatory nie zostaną uruchomione domyślnie. Z Javadoc dla Runtime.exit () :

Sekwencja zamykania maszyny wirtualnej składa się z dwóch faz. W pierwszej fazie wszystkie zarejestrowane haki zamykające, jeśli występują, są uruchamiane w nieokreślonej kolejności i mogą działać jednocześnie aż do ich zakończenia. W drugiej fazie uruchamiane są wszystkie nieproszone finalizatory, jeśli włączono finalizację przy wyjściu. Po wykonaniu tej czynności maszyna wirtualna zatrzymuje się.

Możesz zadzwonić, System.runFinalization()ale to tylko „najlepszy wysiłek, aby ukończyć wszystkie zaległe finalizacje” - nie jest to gwarancja.

Istnieje System.runFinalizersOnExit()metoda, ale nie używaj jej - jest niebezpieczna, dawno przestarzała.


1

Jeśli piszesz aplet Java, możesz przesłonić metodę apletu „destroy ()”. To jest...

 * Called by the browser or applet viewer to inform
 * this applet that it is being reclaimed and that it should destroy
 * any resources that it has allocated. The stop() method
 * will always be called before destroy().

Oczywiście nie to, czego chcesz, ale może być tym, czego szukają inni ludzie.


1

Właśnie myślę o pierwotnym pytaniu ... które, jak sądzę, możemy wyciągnąć z wszystkich innych wyuczonych odpowiedzi, a także z niezbędnej skutecznej Javy Blocha , punkt 7, „Unikaj finalizatorów”, szuka rozwiązania uzasadnionego pytania w sposób, który jest nieodpowiedni dla języka Java ...:

... nie byłoby dość oczywistym rozwiązaniem, aby faktycznie zrobić OP, aby zatrzymać wszystkie obiekty, które muszą zostać zresetowane, w rodzaju „kojec”, do którego wszystkie inne obiekty, które nie mogą być zresetowane, mają odniesienia tylko poprzez pewien rodzaj obiektu akcesorium ...

A potem, kiedy trzeba „zresetować”, odłączasz istniejący kojec i tworzysz nowy: cała sieć obiektów w kojecu jest rzucana w dół, nigdy nie wracać, i pewnego dnia GC zbierze.

Jeśli którykolwiek z tych obiektów jest Closeable(ale nie ma, ale ma closemetodę), możesz umieścić je w Bagkojecu podczas ich tworzenia (i być może otwarcia), a ostatni akt akcesorium przed odcięciem kojenia byłby możliwy przez Closeablesich zamykanie ...?

Kod prawdopodobnie wyglądałby mniej więcej tak:

accessor.getPlaypen().closeCloseables();
accessor.setPlaypen( new Playpen() );

closeCloseablesprawdopodobnie byłaby to metoda blokująca, prawdopodobnie obejmująca zatrzask (np. CountdownLatch), aby poradzić sobie (i odpowiednio poczekać) z dowolnym Runnables/ Callablesw dowolnym wątku specyficznym do Playpenzakończenia, odpowiednio, w szczególności w wątku JavaFX.


0

Chociaż nastąpił znaczny postęp w technologii GC Javy, nadal musisz pamiętać o swoich referencjach. Przychodzą mi na myśl liczne pozornie trywialne wzorce odniesienia, które w rzeczywistości są gniazdami szczurów pod maską.

Z twojego postu nie brzmi to tak, jakbyś próbował wdrożyć metodę resetowania w celu ponownego użycia obiektu (prawda?). Czy twoje obiekty posiadają jakiekolwiek inne zasoby, które muszą zostać oczyszczone (tj. Strumienie, które muszą zostać zamknięte, jakieś pule lub pożyczone obiekty, które muszą zostać zwrócone)? Jeśli martwisz się tylko o zwolnienie pamięci, to ponownie zastanowię się nad strukturą moich obiektów i spróbuję sprawdzić, czy moje obiekty są samodzielnymi strukturami, które zostaną wyczyszczone w czasie GC.



0

Żadna Java nie ma żadnych niszczycieli. Głównym powodem jest to, że w Javie Garbage Collectors pasywnie działają zawsze w tle, a wszystkie obiekty są tworzone w pamięci sterty, czyli tam, gdzie działa GC. muszą jawnie wywoływać funkcję usuwania, ponieważ nie istnieje element podobny do Garbage Collectora.


-3

Kiedyś zajmowałem się głównie C ++ i właśnie to doprowadziło mnie do poszukiwania destruktora. Teraz dużo używam JAVA. To, co zrobiłem, i może nie jest to najlepszy przypadek dla wszystkich, ale zaimplementowałem własny destruktor, resetując wszystkie wartości do 0 lub domyślnie za pomocą funkcji.

Przykład:

public myDestructor() {

variableA = 0; //INT
variableB = 0.0; //DOUBLE & FLOAT
variableC = "NO NAME ENTERED"; //TEXT & STRING
variableD = false; //BOOL

}

Idealnie nie zadziała to we wszystkich sytuacjach, ale tam, gdzie są zmienne globalne, będzie działać, dopóki nie będzie ich mnóstwo.

Wiem, że nie jestem najlepszym programistą Java, ale wydaje mi się, że to działa.


Staraj się częściej używać niezmiennych obiektów, po „zdobyciu” wszystko będzie miało więcej sensu :)
R. van Twisk,

5
Nie jest to tak bardzo złe, jak bezcelowe - tj. Nie osiąga niczego. Jeśli twój program wymaga zresetowania typów surowych, aby działał poprawnie, wówczas instancje klas mają niepoprawny zakres, co oznacza, że ​​prawdopodobnie przypisujesz właściwości istniejącego obiektu do właściwości nowego obiektu, bez tworzenia nowego obiektu ().
simo.3792

1
Tyle że istnieje wiele potrzeb dotyczących resetowania zmiennych. Wybrałem nazwę destructor, ponieważ pasuje do tego, co robię. Osiąga coś, tylko nic nie rozumiesz
ChristianGLong,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.