Есть ли деструктор для Java? Кажется, я не могу найти никакой документации по этому вопросу. Если нет, как я могу достичь того же эффекта?
Чтобы сделать мой вопрос более конкретным, я пишу приложение, которое работает с данными, и в спецификации говорится, что должна быть кнопка «сброс», которая возвращает приложение в исходное только что запущенное состояние. Однако все данные должны быть «живыми», если приложение не закрыто или не нажата кнопка сброса.
Будучи обычно программистом на C / C ++, я думал, что это будет тривиально реализовать. (И, следовательно, я планировал реализовать его в последний раз.) Я структурировал свою программу так, чтобы все объекты с возможностью сброса находились в одном классе, чтобы я мог просто уничтожить все «живые» объекты при нажатии кнопки сброса.
Я думал, что если бы все, что я делал, это просто разыменовывал данные и ждал, когда сборщик мусора соберет их, не будет ли утечка памяти, если мой пользователь неоднократно вводит данные и нажимает кнопку сброса? Я также думал, что поскольку Java достаточно зрел как язык, должен быть способ предотвратить это или изящно справиться с этим.
Ответы:
Поскольку Java является языком сборки мусора, вы не можете предсказать, когда (или даже если) объект будет уничтожен. Следовательно, нет прямого эквивалента деструктора.
Существует наследуемый метод
finalize
, который вызывается, но он вызывается исключительно по усмотрению сборщика мусора. Таким образом, для классов, которые должны явно привести в порядок, соглашение состоит в том, чтобы определить метод close и использовать finalize только для проверки работоспособности (то есть, если close не был вызван, сделайте это сейчас и зарегистрируйте ошибку).Был вопрос, который недавно породил всестороннее обсуждение финализации , так что это должно обеспечить большую глубину при необходимости ...
источник
finalize
метод устарел в Java 9.Посмотрите на инструкцию " попробуй с ресурсами" . Например:
Здесь ресурс, который больше не нужен, освобождается в
BufferedReader.close()
методе. Вы можете создать свой собственный класс, который реализуетAutoCloseable
и использовать его аналогичным образом.Это утверждение более ограничено, чем
finalize
с точки зрения структурирования кода, но в то же время делает код более простым для понимания и сопровождения. Кроме того, нет никакой гарантии, чтоfinalize
метод вызывается вообще во время работы приложения.источник
try
иfinally
используются для принудительного вызоваobj.finalize()
. И даже эта настройка не решает проблему, поставленную OP: уничтожение объекта в середине программы, вызванное кнопкой «перезагрузки».Нет, здесь нет деструкторов. Причина в том, что все объекты Java выделены в куче и мусор. Без явного освобождения (т. Е. Оператора удаления C ++) не существует разумного способа реализации реальных деструкторов.
Java поддерживает финализаторы, но они предназначены для использования только в качестве защиты для объектов, содержащих дескриптор собственных ресурсов, таких как сокеты, дескрипторы файлов, дескрипторы окон и т. Д. Когда сборщик мусора собирает объект без финализатора, он просто отмечает память регион как свободный и все тут. Когда у объекта есть финализатор, он сначала копируется во временное местоположение (помните, мы собираем мусор здесь), затем он помещается в очередь, ожидающую завершения, а затем поток финализатора опрашивает очередь с очень низким приоритетом. и запускает финализатор.
Когда приложение закрывается, JVM останавливается, не дожидаясь завершения ожидающих объектов, поэтому практически нет никаких гарантий, что ваши финализаторы когда-либо будут работать.
источник
Следует избегать использования методов finalize () . Они не являются надежным механизмом очистки ресурсов, и их использование может привести к проблемам в сборщике мусора.
Если вам требуется вызов освобождения в вашем объекте, скажем, для освобождения ресурсов, используйте явный вызов метода. Это соглашение можно увидеть в существующих API (например, Closeable , Graphics.dispose () , Widget.dispose () ) и обычно вызывается через try / finally.
Попытки использовать удаленный объект должны вызвать исключение времени выполнения (см. IllegalStateException ).
РЕДАКТИРОВАТЬ:
Как правило, все, что вам нужно сделать, это разыменовать объекты - по крайней мере, так оно и должно работать. Если вы беспокоитесь о сборке мусора, ознакомьтесь с настройкой сборки мусора виртуальной машины Java SE 6 HotSpot [tm] (или эквивалентным документом для вашей версии JVM).
источник
class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
С выпуском Java 1.7 у вас теперь есть дополнительная опция использования
try-with-resources
блока. Например,Если выполнить этот класс,
c.close()
будет выполняться , когдаtry
блок остается, и до того , какcatch
иfinally
блоки выполняются. В отличие от случая,finalize()
методclose()
гарантированно будет выполнен. Однако нет необходимости выполнять это явно вfinally
предложении.источник
finalize()
исполнения нетЯ полностью согласен с другими ответами, говоря не полагаться на выполнение финализации.
В дополнение к блокам try-catch-finally вы можете использовать Runtime # addShutdownHook (представленный в Java 1.3) для выполнения окончательных очисток в вашей программе.
Это не то же самое, что деструкторы , но можно реализовать ловушку отключения, в которой зарегистрированы объекты прослушивателя, для которых можно вызывать методы очистки (закрывать постоянные соединения с базой данных, удалять блокировки файлов и т. Д.) - то, что обычно делается в деструкторы . Опять же - это не замена деструкторам, но в некоторых случаях вы можете достичь желаемой функциональности с этим.
Преимущество этого заключается в том, что поведение деконструкции слабо связано с остальной частью вашей программы.
источник
Нет,
java.lang.Object#finalize
это самое близкое, что вы можете получить.Однако когда (и если) он вызывается, это не гарантируется.
Видеть:
java.lang.Runtime#runFinalizersOnExit(boolean)
источник
Во-первых, обратите внимание, что, поскольку Java является сборщиком мусора, редко нужно что-либо делать с уничтожением объектов. Во-первых, потому что у вас обычно нет никаких управляемых ресурсов для освобождения, а во-вторых, потому что вы не можете предсказать, когда или если это произойдет, поэтому это неуместно для вещей, которые должны произойти, «как только никто больше не использует мой объект ».
Вы можете быть уведомлены после того, как объект был уничтожен, используя java.lang.ref.PhantomReference (фактически, сказать, что он был уничтожен, может быть немного неточным, но если фантомная ссылка на него помещена в очередь, то он больше не подлежит восстановлению, что обычно составляет тоже самое). Общее использование:
Есть также finalize (), который выглядит как деструктор, но не ведет себя как один. Обычно это не очень хороший вариант.
источник
finalize()
Функция деструктор.Тем не менее, он не должен обычно использоваться, потому что он вызывается после GC, и вы не можете сказать, когда это произойдет (если когда-либо).
Кроме того, требуется более одного GC для освобождения объектов, которые имеют
finalize()
.Вы должны попытаться очистить логические места в вашем коде, используя
try{...} finally{...}
операторы!источник
Я согласен с большинством ответов.
Вы не должны зависеть полностью от либо
finalize
илиShutdownHook
финализации
JVM не гарантирует, когда этот
finalize()
метод будет вызван.finalize()
вызывается только один раз потоком GC. Если объект восстанавливается из метода финализации, онfinalize
больше не будет вызываться.В вашем приложении вы можете иметь несколько живых объектов, для которых сборка мусора никогда не вызывается.
Все,
Exception
что выброшено методом финализации, игнорируется потоком GCSystem.runFinalization(true)
иRuntime.getRuntime().runFinalization(true)
методы увеличивают вероятность вызоваfinalize()
метода, но теперь эти два метода устарели. Эти методы очень опасны из-за недостаточной безопасности потока и возможного создания тупика.shutdownHooks
Виртуальная машина Java отключается в ответ на два вида событий:
System.exit
вызывается метод exit (эквивалентно ), илиОтключающие крюки также должны быстро закончить свою работу. Когда программа вызывает выход, ожидается, что виртуальная машина будет быстро закрыта и завершит работу.
Но даже в документации Oracle указано, что
Это происходит, когда виртуальная машина завершается извне, например, при
SIGKILL
сигнале в Unix или приTerminateProcess
вызове в Microsoft Windows. Виртуальная машина также может прервать работу, если собственный метод не работает, например, из-за повреждения внутренних структур данных или попытки доступа к несуществующей памяти. Если виртуальная машина прерывает работу, то нельзя гарантировать, будут ли запущены какие-либо перехватчики завершения работы.Вывод : используйте
try{} catch{} finally{}
блоки соответствующим образом и высвобождайте критические ресурсы вfinally(}
блоке. Во время освобождения ресурсов вfinally{}
блоке catchException
иThrowable
.источник
Если вы беспокоитесь только о памяти, не надо. Просто доверьтесь GC, он делает достойную работу. Я действительно видел кое-что о том, что он настолько эффективен, что для производительности было бы лучше создавать кучи крошечных объектов, чем использовать большие массивы в некоторых случаях.
источник
Возможно, вы можете использовать блок try ... finally, чтобы завершить объект в потоке управления, в котором вы используете объект. Конечно, это не происходит автоматически, но и уничтожение в C ++ не происходит. Вы часто видите закрытие ресурсов в блоке finally.
источник
В Ломбоке есть аннотация @Cleanup, которая в основном напоминает деструкторы C ++:
При обработке (во время компиляции) Lombok вставляет соответствующий
try-finally
блок, которыйresource.close()
вызывается, когда выполнение выходит из области видимости переменной. Вы также можете явно указать другой метод освобождения ресурса, напримерresource.dispose()
:источник
@Cleanup
Ближайшим эквивалентом деструктора в Java является метод finalize () . Большая разница с традиционным деструктором заключается в том, что вы не можете быть уверены, когда он будет вызван, поскольку это является обязанностью сборщика мусора. Я настоятельно рекомендую внимательно прочитать это перед использованием, поскольку ваши типичные шаблоны RAIA для файловых дескрипторов и т. Д. Не будут надежно работать с finalize ().
источник
Здесь много хороших ответов, но есть дополнительная информация о том, почему вы должны избегать использования finalize () .
Если JVM завершает работу из-за
System.exit()
илиRuntime.getRuntime().exit()
, финализаторы не будут запускаться по умолчанию. Из Javadoc для Runtime.exit () :Вы можете позвонить,
System.runFinalization()
но это только делает все возможное, чтобы завершить все незавершенные финализации - не гарантия.Есть
System.runFinalizersOnExit()
метод, но не используйте его - он небезопасен, давно устарел.источник
Если вы пишете Java-апплет, вы можете переопределить метод Applet "destroy ()". Это...
Очевидно, не то, что вы хотите, но может быть то, что ищут другие люди.
источник
Просто подумав об исходном вопросе ... который, я думаю, мы можем сделать вывод из всех других изученных ответов, а также из существенной Блоха Эффективной Java , пункт 7, «Избегать финализаторов», ищет решение законного вопроса таким образом, чтобы не подходит для языка Java ...:
... не было бы довольно очевидным решением сделать то, что на самом деле хочет ОП - сохранить все ваши объекты, которые должны быть сброшены, в виде «игрового автомата», на который все другие не сбрасываемые объекты имеют ссылки только через какой-то вид объекта доступа ...
И затем, когда вам нужно «сбросить», вы отключаете существующий манеж и создаете новый: вся паутина объектов в манеже отбрасывается по течению, никогда не возвращается и однажды будет собрана GC.
Если какой-либо из этих объектов
Closeable
(или нет, но у него естьclose
метод), вы можете поместить ихBag
в манеж в момент их создания (и, возможно, открытия), и последним действием аксессора перед тем, как отрезать манеж, будет через всеCloseables
закрывающие их ...?Код, вероятно, будет выглядеть примерно так:
closeCloseables
Вероятно, это будет метод блокировки, возможно, включающий защелку (напримерCountdownLatch
), для обработки (и ожидания в случае необходимости) любыхRunnables
/Callables
в любых потоках, специфичныхPlaypen
для завершения, в зависимости от ситуации, в частности в потоке JavaFX.источник
Хотя в технологии Java GC были достигнуты значительные успехи, вы все равно должны помнить о своих ссылках. Вспоминаются многочисленные случаи, казалось бы, тривиальных эталонных образцов, которые на самом деле являются гнездами крыс под капотом.
Из вашего поста не похоже, что вы пытаетесь реализовать метод сброса для повторного использования объекта (верно?). Содержат ли ваши объекты какие-либо другие типы ресурсов, которые необходимо очистить (т. Е. Потоки, которые должны быть закрыты, любые объекты пула или заимствованные объекты, которые должны быть возвращены)? Если единственное, что вас беспокоит, это освобождение памяти, то я бы пересмотрел структуру своего объекта и попытался бы убедиться, что мои объекты являются автономными структурами, которые будут очищены во время GC.
источник
В Java нет точно класса деструктора, класс уничтожается в Java автоматически сборщиком мусора. но вы можете сделать это, используя ниже один, но это не совсем то же самое:
финализации ()
Был вопрос, который породил углубленное обсуждение финализации , так что вы должны получить больше глубины, если требуется ...
источник
Ни в Java нет деструкторов. Основной причиной этого в Java являются сборщики мусора, которые всегда пассивно работают в фоновом режиме, и все объекты создаются в динамической памяти, где и работает GC. В c ++ мы Явно нужно вызвать функцию удаления, так как нет такой вещи, как сборщик мусора.
источник
Раньше я в основном имел дело с C ++, и это также привело меня к поиску деструктора. Я сейчас использую JAVA. То, что я сделал, и это, возможно, не лучший случай для всех, но я реализовал свой собственный деструктор, сбросив все значения до 0 или там по умолчанию через функцию.
Пример:
В идеале это не будет работать для всех ситуаций, но там, где есть глобальные переменные, это будет работать, пока у вас их нет.
Я знаю, что я не лучший Java-программист, но, похоже, он мне подходит.
источник