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ąć.
Odpowiedzi:
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ę ...
źródło
finalize
metoda została wycofana w Javie 9.Spójrz na try-with-resources . Na przykład:
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ąAutoCloseable
i używa w podobny sposób.To stwierdzenie jest bardziej ograniczone niż
finalize
w zakresie struktury kodu, ale jednocześnie ułatwia zrozumienie i utrzymanie kodu. Ponadto nie ma gwarancji, żefinalize
metoda zostanie w ogóle wywołana w czasie trwania aplikacji.źródło
try
ifinally
służy do wymuszenia wywołaniaobj.finalize()
. I nawet ta konfiguracja nie rozwiązuje problemu związanego z OP: niszczenie obiektów w trakcie programu uruchamiane przyciskiem „reset”.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ć.
źródło
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.
Próby użycia rozmieszczonego obiektu powinny wygenerować wyjątek czasu wykonywania (patrz wyjątek IllegalStateException ).
EDYTOWAĆ:
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).
źródło
class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
Po wydaniu Java 1.7 masz teraz dodatkową opcję korzystania z
try-with-resources
bloku. Na przykład,Jeśli wykonasz tę klasę,
c.close()
zostanie wykonana, gdytry
blok zostanie opuszczony, a przed wykonaniem blokówcatch
ifinally
. W przeciwieństwie do tejfinalize()
metody,close()
gwarantuje się, że zostanie wykonana. Jednak nie ma potrzeby wykonywania go jawnie wfinally
klauzuli.źródło
finalize()
wykonaniaW 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.
źródło
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)
źródło
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:
Istnieje również finalize (), który wygląda jak destruktor, ale nie zachowuje się jak jeden. Zwykle nie jest to dobra opcja.
źródło
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!źródło
Zgadzam się z większością odpowiedzi.
Nie powinieneś w pełni polegać na którymkolwiek
finalize
lubShutdownHook
sfinalizować
JVM nie gwarantuje, kiedy ta
finalize()
metoda zostanie wywołana.finalize()
jest wywoływany tylko raz przez wątek GC. Jeśli obiekt ożywi się po sfinalizowaniu metody,finalize
nie zostanie ponownie wywołany.W twojej aplikacji możesz mieć jakieś obiekty aktywne, na których nigdy nie wywoływane jest czyszczenie pamięci.
Wszystko,
Exception
co zostanie wyrzucone metodą finalizującą, jest ignorowane przez wątek GCSystem.runFinalization(true)
iRuntime.getRuntime().runFinalization(true)
metody zwiększają prawdopodobieństwo wywołaniafinalize()
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
Maszyna wirtualna Java wyłącza się w odpowiedzi na dwa rodzaje zdarzeń:
System.exit
wywoływana jest metoda ) lubHaki 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
Dzieje się tak, gdy maszyna wirtualna zostaje zakończona zewnętrznie, na przykład z
SIGKILL
sygnałem w systemie Unix lubTerminateProcess
wywoł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 wfinally(}
bloku. Podczas uwalniania zasobów wfinally{}
bloku łapException
iThrowable
.źródło
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.
źródło
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.
źródło
W Lombok znajduje się adnotacja @Cleanup, która w większości przypomina destruktory C ++:
Podczas przetwarzania (w czasie kompilacji) Lombok wstawia odpowiedni
try-finally
blok, abyresource.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()
:źródło
@Cleanup
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 ().
źródło
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()
lubRuntime.getRuntime().exit()
, finalizatory nie zostaną uruchomione domyślnie. Z Javadoc dla Runtime.exit () :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.źródło
Jeśli piszesz aplet Java, możesz przesłonić metodę apletu „destroy ()”. To jest...
Oczywiście nie to, czego chcesz, ale może być tym, czego szukają inni ludzie.
źródło
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 maclose
metodę), możesz umieścić je wBag
kojecu podczas ich tworzenia (i być może otwarcia), a ostatni akt akcesorium przed odcięciem kojenia byłby możliwy przezCloseables
ich zamykanie ...?Kod prawdopodobnie wyglądałby mniej więcej tak:
closeCloseables
prawdopodobnie byłaby to metoda blokująca, prawdopodobnie obejmująca zatrzask (np.CountdownLatch
), aby poradzić sobie (i odpowiednio poczekać) z dowolnymRunnables
/Callables
w dowolnym wątku specyficznym doPlaypen
zakończenia, odpowiednio, w szczególności w wątku JavaFX.źródło
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.
źródło
W Javie nie ma dokładnie klasy destruktora, klasa zniszczona w java automatycznie przez moduł wyrzucania elementów bezużytecznych. ale możesz to zrobić, używając poniżej jednego, ale nie jest to dokładnie to samo:
sfinalizować()
Pojawiło się pytanie, które zrodziło pogłębioną dyskusję na temat finalizacji , aby w razie potrzeby uzyskać więcej głębi ...
źródło
Ż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.
źródło
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:
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.
źródło