Во время освобождения памяти которую занимает объект у него будет вызван метод finalize

Обновлено: 02.07.2024

Мне нужно знать, когда finalize() метод вызывается в JVM . Я создал тестовый класс, который записывает в файл при finalize() вызове метода путем его переопределения. Это не выполнено. Кто-нибудь может сказать мне причину, почему это не выполняется?

Как примечание: финализация помечена как устаревшая в Java 9 если что-то имеет ссылку на ваш объект или даже класс. finalize() и сборка мусора не имеет никакого влияния.

В общем, лучше не полагаться на finalize() уборку и т. Д.

Согласно Javadoc (который стоило бы прочитать), это:

Вызывается сборщиком мусора на объекте, когда сборщик мусора определяет, что больше нет ссылок на объект.

Как отметил Иоахим, это может никогда не произойти в жизни программы, если объект всегда доступен.

Кроме того, сборщик мусора не гарантированно работает в любое конкретное время. В общем, то, что я пытаюсь сказать, это finalize() , вероятно, не лучший метод для использования в целом, если нет необходимости в чем-то конкретном.

Другими словами (просто для разъяснения будущим читателям), он никогда не вызывается для основного класса, так как, когда основной класс закрывается, мусор собирать не нужно. Операционная система очищает все, что использовалось приложением. «не лучший метод для использования . если нет необходимости в чем-то конкретном» - это предложение применимо к 100% всего, поэтому оно не помогает. Ответ Иоахима Зауэра намного лучше @ Zom-B ваш пример полезен для пояснения, но просто для того, чтобы быть педантичным, предположительно его можно было бы вызвать в основном классе, если основной класс создает поток, не являющийся демоном, а затем возвращает? @MarkJeronimus - На самом деле, это не имеет значения. finalize() Метод на для основного класса вызывается , когда >> << экземпляр класса является сбор мусора, не тогда , когда основной метод завершается. И, кроме того, главный класс может быть собран мусором до завершения приложения; например, в многопоточном приложении, где «основной» поток создает другие потоки, а затем возвращает. (На практике потребуется нестандартный загрузчик классов . )

finalize Метод вызывается , когда объект собирается получить мусор. Это может произойти в любое время после того, как он получил право на сборку мусора.

Обратите внимание, что вполне возможно, что объект никогда не получает мусор (и, следовательно finalize , никогда не вызывается). Это может произойти, когда объект никогда не становится подходящим для gc (потому что он доступен в течение всего времени жизни JVM) или когда фактически не выполняется сборка мусора между моментом, когда объект становится приемлемым, и временем, когда JVM прекращает работу (это часто происходит с простыми тестовые программы).

Есть способы заставить JVM работать finalize с объектами, которые еще не были вызваны, но их использование тоже не очень хорошая идея (гарантии этого метода также не очень сильны).

Если вы полагаетесь на finalize правильную работу вашего приложения, то вы делаете что-то не так. finalize следует использовать только для очистки (обычно не Java) ресурсов. И это именно потому, что JVM не гарантирует, что finalize когда-либо вызывается на любом объекте.

@Rajesh. Нет. Это не проблема "продолжительности жизни". Вы можете поместить вашу программу в бесконечный цикл (на годы), и если сборщик мусора не нужен, он никогда не запустится. @VikasVerma: идеальная замена - ничто: они вам не нужны. Единственный случай, когда это имеет смысл, - это если ваш класс управляет каким-то внешним ресурсом (например, TCP / IP-соединением, файлом . всем, что не может обработать Java GC). В этих случаях Closable интерфейс (и идея, лежащая в его основе), вероятно, то, что вам нужно: .close() закройте / отмените ресурс и потребуйте, чтобы пользователь вашего класса вызвал его в нужное время. Вы , возможно , хотите добавить finalize метод «просто быть сохранить», но это будет скорее инструмент отладки , чем фактическое исправление (потому что это не достаточно надежным). @Dragonborn: на самом деле это совсем другой вопрос, и его следует задавать отдельно. Существуют перехватчики отключения, но они не гарантируются, если JVM неожиданно завершает работу (иначе происходит сбой). Но их гарантии значительно сильнее, чем гарантии для финализаторов (и они также безопаснее). В последнем абзаце говорится, что использовать его только для очистки ресурсов, хотя нет никаких гарантий, что он когда-либо будет вызван. Этот оптимизм говорит? Я бы предположил, что что-то ненадежное, так как это также не подходит для очистки ресурсов. Финализаторы иногда могут сохранить день . У меня был случай, когда сторонняя библиотека использовала FileInputStream, никогда не закрывая его. Мой код вызывал код библиотеки, а затем попытался переместить файл, но не удалось, потому что он все еще был открыт. Мне пришлось принудительно вызвать call, System.gc() чтобы вызвать FileInputStream :: finalize (), затем я мог переместить файл.
  • каждый класс наследует finalize() метод от java.lang.Object
  • метод вызывается сборщиком мусора, когда он определяет, что ссылки на объект больше не существуют
  • метод Object finalize не выполняет никаких действий, но может быть переопределен любым классом
  • обычно он должен быть переопределен для очистки не Java-ресурсов, то есть закрытия файла
  • при переопределении finalize() хорошей практикой программирования является использование оператора try-catch-finally и всегда вызывать super.finalize() . Это мера безопасности, гарантирующая, что вы случайно не пропустите закрытие ресурса, используемого объектами, вызывающими класс

  • любое исключение, возникающее finalize() во время сборки мусора, останавливает завершение, но в противном случае игнорируется

  • finalize() никогда не запускается более одного раза на любом объекте

Вы также можете проверить эту статью:

Так как runFinalizerOnExit () НЕ является потокобезопасным, то, что можно сделать, это Runtime.getRuntime (). AddShutdownHook (new Thread () >); в конструкторе класса. @ Ustaman Sangat Это способ сделать это, но помните, что он устанавливает ссылку на ваш экземпляр из shutdownHook, который в значительной степени гарантирует, что ваш класс никогда не будет собирать мусор. Другими словами, это утечка памяти. @pieroxy, в то время как я согласен со всеми остальными здесь относительно того, чтобы не использовать finalize () ни для чего, я не понимаю, почему должна быть ссылка из ловушки завершения работы. Можно иметь мягкую ссылку.

Метод Java finalize() не является деструктором и не должен использоваться для обработки логики, от которой зависит ваше приложение. Спецификация Java утверждает, что нет гарантии, что finalize метод вызывается вообще во время работы приложения.

Вероятно, вам нужно сочетание finally и метод очистки, как в:

Проверьте Effective Java, 2-е издание, стр. 27. Пункт 7: Избегайте финализаторов

Финализаторы непредсказуемы, часто опасны и, как правило, не нужны. никогда не делайте что-нибудь критичное по времени в финализаторе. никогда не зависите от финализатора для обновления критического постоянного состояния.

Чтобы завершить ресурс, используйте вместо этого try-finally:

Это предполагает, что время жизни объекта находится в области действия одной функции. Что, конечно, не тот случай, на который ссылается ФП, и не тот случай, который вообще нужен кому-то. Подумайте «подсчет возвращаемого значения механизма кэширования». Вы хотите освободить запись кэша при освобождении последней ссылки, но не знаете, когда освобождается последняя ссылка. finalize () может уменьшить счетчик ссылок, например . но если вам требуется, чтобы ваши пользователи явно вызывали свободную функцию, вы просите утечки памяти. обычно я просто делаю и то, и другое (функция релиза + двойная проверка в финализации . ) .

Когда finalize() метод вызывается в Java?

Метод finalize будет вызван после того, как GC обнаружит, что объект более недоступен, и до того, как он фактически освободит память, используемую объектом.

Если объект никогда не станет недоступным, finalize() его никогда не вызовут.

Если GC не работает, то finalize() никогда не может быть вызван. (Обычно GC запускается только тогда, когда JVM решает, что мусора, вероятно, достаточно, чтобы оно того стоило.)

Может потребоваться более одного цикла GC, прежде чем GC определит, что определенный объект недоступен. (Java GC, как правило, являются сборщиками поколений . )

Как только GC обнаруживает, что объект недоступен и завершен, он помещается в очередь завершения. Завершение обычно происходит асинхронно с обычным GC.

(Спецификация JVM фактически позволяет JVM никогда не запускать финализаторы . при условии, что она не освобождает пространство, используемое объектами. JVM, который был реализован таким образом, будет поврежден / бесполезен, но если это поведение "разрешено" .)

В результате неразумно полагаться на завершение, чтобы делать то, что должно быть сделано в определенные сроки. Это «лучшая практика» - не использовать их вообще. Должен быть лучший (то есть более надежный) способ сделать то, что вы пытаетесь сделать в finalize() методе.

Единственное законное использование для финализации - очистить ресурсы, связанные с объектами, которые были потеряны кодом приложения. Даже тогда вы должны попытаться написать код приложения, чтобы он не терял объекты в первую очередь. (Например, используйте Java 7+ try-with-resources, чтобы close() всегда вызывать . )

Я создал тестовый класс, который записывает в файл при вызове метода finalize (), переопределяя его. Это не выполнено. Кто-нибудь может сказать мне причину, почему это не выполняется?

Трудно сказать, но есть несколько возможностей:

  • Объект не является сборщиком мусора, потому что он все еще доступен.
  • Объект не является сборщиком мусора, потому что сборщик мусора не запускается до завершения теста.
  • Объект найден GC и помещен GC в очередь на финализацию, но финализация не завершена до завершения теста.

Поскольку существует неопределенность в вызове метода finalize () из JVM (не уверен, будет ли выполнен finalize (), который переопределяется, будет или нет), для целей изучения лучший способ наблюдать за тем, что происходит при вызове finalize (), состоит в том, чтобы заставить JVM вызывать сборщик мусора командой System.gc() .

В частности, finalize () вызывается, когда объект больше не используется. Но когда мы пытаемся вызвать его, создавая новые объекты, нет уверенности в его вызове. Поэтому для определенности мы создаем null объект, c который, очевидно, не будет использоваться в будущем, поэтому мы видим c вызов объекта finalize.

пример

Вывод

Примечание. Даже после печати до 70 и после того, как объект b не используется в программе, существует неопределенность, что b очищается или не удаляется JVM, так как «Вызванный метод финализации в классе Bike . » не печатается.

Вызов System.gc(); не является гарантией того, что сборка мусора действительно будет запущена. Также не гарантируется , что тип коллекции будет работать. Уместно, так как большинство Java GC являются сборщиками поколений.

finalize распечатает счет для создания класса.

Как вы видете. Следующий вывод показывает, что gc был выполнен первый раз, когда счетчик классов равен 36.

В последнее время, борясь с методами финализатора (чтобы избавиться от пулов соединений во время тестирования), я должен сказать, что финализатору не хватает многих вещей. Используя VisualVM для наблюдения, а также используя слабые ссылки для отслеживания реального взаимодействия, я обнаружил, что в среде Java 8 верно следующее: Oracle JDK, Ubuntu 15):

  • Finalize не вызывается сразу, как только Finalizer (часть GC) владеет ссылкой.
  • Сборщик мусора по умолчанию объединяет недоступные объекты
  • Finalize вызывается массово, указывая на детали реализации, что существует определенный этап, когда сборщик мусора освобождает ресурсы.
  • Вызов System.gc () часто не приводит к тому, что объекты завершаются чаще, а просто приводит к тому, что Finalizer быстрее узнает о недоступном объекте
  • Создание дампа потока почти всегда приводит к запуску финализатора из-за высоких издержек кучи во время выполнения дампа кучи или какого-либо другого внутреннего механизма
  • Швы завершения должны быть связаны либо с требованиями к памяти (освобождают больше памяти), либо со списком объектов, помеченных для роста завершения до определенного внутреннего предела. Так что, если у вас есть много объектов, которые будут завершены, фаза завершения будет запускаться чаще и раньше, по сравнению с несколькими
  • Были обстоятельства, когда System.gc () вызывал финализацию напрямую, но только если ссылка была локальной и недолгой. Это может быть связано с поколением.

Последняя мысль

Метод Finalize ненадежен, но может использоваться только для одной цели. Вы можете убедиться, что объект был закрыт или утилизирован до того, как он был собран мусором, что позволяет реализовать отказоустойчивый объект, если объекты с более сложным жизненным циклом, включающим действие с истекшим сроком службы, обрабатываются правильно. Это единственная причина, по которой я могу придумать, стоит того, чтобы ее переопределить.

Объект получает право на сборку мусора или сборщик мусора, если он недоступен из каких-либо активных потоков или статических ссылок, другими словами, вы можете сказать, что объект получает право на сборку мусора, если все его ссылки равны нулю. Циклические зависимости не считаются ссылками, поэтому, если у объекта A есть ссылка на объект B, а у объекта B есть ссылка на объект A, и у них нет никакой другой активной ссылки, тогда и объекты A, и B будут иметь право на сборку мусора. Обычно объект получает право на сборку мусора в Java в следующих случаях:

  1. Все ссылки на этот объект явно установлены на нуль, например, объект = нуль
  2. Объект создается внутри блока, и ссылка выходит из области действия после выхода из этого блока.
  3. Родительскому объекту присваивается значение NULL, если объект содержит ссылку на другой объект и когда вы устанавливаете нулевую ссылку на объект контейнера, дочерний или содержащийся объект автоматически получает право на сборку мусора.
  4. Если объект имеет только живые ссылки через WeakHashMap, он будет иметь право на сборку мусора.
Если final поле объекта используется многократно во время медленного вычисления, и объект никогда не будет использоваться после этого, будет ли объект сохранен живым до тех пор, пока исходный код не запросит поле, или JIT может скопировать поле в временная переменная, а затем отказаться от объекта до вычисления? @supercat: оптимизатор может переписать код в форму, где объект не создается в первую очередь; в этом случае он может быть завершен сразу после завершения конструктора, если только синхронизация не вызовет упорядочение между использованием объекта и финализатором. @supercat: JIT не запускает финализацию, он просто упорядочивает код так, чтобы он не сохранял ссылку, хотя, возможно, было бы полезно напрямую поставить в очередь FinalizerReference , так что ему не нужен цикл GC, чтобы выяснить, что нет Ссылки. Синхронизация достаточна для того, чтобы обеспечить связь «до того как случится» ; поскольку финализация может (на самом деле) выполняться в другом потоке, она все равно формально необходима в любом случае. Java 9 собирается добавить Reference.reachabilityFence . @Holger: Если JIT оптимизирует создание объекта, то Finalize будет вызван только один, если JIT создаст код, который сделал это напрямую. Можно ли ожидать код синхронизации для объектов, которые ожидают использования только в одном потоке? Если объект выполняет какое-либо действие, которое необходимо отменить перед тем, как его прекратить (например, открытие соединения с сокетом и получение исключительного использования для ресурса на другом конце), если финализатор закроет соединение, пока код все еще использует сокет, будет катастрофой , Было бы нормально, чтобы код использовал синхронизацию .

Метод финализации не гарантирован. Этот метод вызывается, когда объект получает право на сборщик мусора. Есть много ситуаций, когда объекты не могут быть собраны мусором.

Неправильно. Вы говорите, что объект завершается, когда он становится недоступным. Это на самом деле вызывается, когда метод фактически собран.

Иногда, когда он уничтожен, объект должен совершить действие. Например, если объект имеет не-Java-ресурс, такой как дескриптор файла или шрифт, вы можете проверить, что эти ресурсы освобождены, прежде чем уничтожать объект. Для управления такими ситуациями java предлагает механизм, называемый «финализация». Завершив его, вы можете определить конкретные действия, которые происходят, когда объект собирается удалить из сборщика мусора. Чтобы добавить финализатор в класс, просто определите метод finalize () . Время выполнения Java вызывает этот метод всякий раз, когда он собирается удалить объект этого класса. В методе финализации () вы указываете действия, которые должны быть выполнены перед уничтожением объекта. Сборщик мусора периодически ищет объекты, которые больше не ссылаются ни на какое запущенное состояние или косвенно на любой другой объект со ссылкой. Перед освобождением актива среда выполнения Java вызывает метод finalize () для объекта. finalize () имеет следующую общую форму:

С помощью защищенного ключевого слова доступ к finalize () по коду вне его класса запрещен. Важно понимать, что finalize () вызывается непосредственно перед сборкой мусора. Например, он не вызывается, когда объект покидает область видимости. Это означает, что вы не можете знать, когда или если будет выполнено finalize () . В результате программа должна предоставлять другие средства для освобождения системных ресурсов или других ресурсов, используемых объектом. Вы не должны полагаться на finalize () для нормального запуска программы.

Узнайте о методе finalize Java и о том, почему его не следует использовать.

1. Обзор

В этом уроке мы сосредоточимся на основном аспекте языка Java – методе finalize , предоставляемом корневым классом Object .

Проще говоря, это вызывается перед сборкой мусора для конкретного объекта.

2. Использование финализаторов

Метод finalize() называется финализатором.

Финализаторы вызываются, когда JVM выясняет, что этот конкретный экземпляр должен быть собран как мусор. Такой финализатор может выполнять любые операции, в том числе возвращать объект к жизни.

Однако основная цель финализатора состоит в том, чтобы освободить ресурсы, используемые объектами, прежде чем они будут удалены из памяти. Финализатор может работать в качестве основного механизма для операций очистки или в качестве защитной сети, когда другие методы не работают.

Чтобы понять, как работает финализатор, давайте взглянем на объявление класса:

Класс Finalizable имеет поле reader , которое ссылается на закрываемый ресурс. Когда объект создается из этого класса, он создает новый BufferedReader экземпляр, считывающий из файла в пути к классу.

Такой экземпляр используется в методе read First Line для извлечения первой строки в данном файле. Обратите внимание, что считыватель не закрыт в данном коде.

Мы можем сделать это с помощью финализатора:

Легко видеть, что финализатор объявляется так же, как и любой обычный метод экземпляра.

На самом деле время, в течение которого сборщик мусора вызывает finalize, зависит от реализации JVM и условий системы, которые находятся вне нашего контроля.

Чтобы сбор мусора происходил на месте, мы воспользуемся методом System.gc . В реальных системах мы никогда не должны ссылаться на это явно по ряду причин:

  1. Это дорого стоит
  2. Это не сразу запускает сборку мусора – это просто подсказка для JVM, чтобы запустить GC
  3. JVM лучше знает, когда нужно вызвать GC

Если нам нужно заставить GC, мы можем использовать для этого jconsole .

Ниже приведен тестовый пример, демонстрирующий работу финализатора:

В первом операторе создается объект Finalizable , затем вызывается метод read First Line . Этот объект не присваивается какой-либо переменной, поэтому он имеет право на сборку мусора при вызове метода System.gc .

Утверждение в тесте проверяет содержимое входного файла и используется только для того, чтобы доказать, что наш пользовательский класс работает должным образом.

До этого момента финализаторы выглядят как отличный способ для операций перед уничтожением. Однако это не совсем так.

В следующем разделе мы увидим, почему следует избегать их использования.

3. Избегайте финализаторов

Несмотря на преимущества, которые они приносят, финализаторы имеют много недостатков.

3.1. Недостатки финализаторов

Давайте рассмотрим несколько проблем, с которыми мы столкнемся при использовании финализаторов для выполнения критических действий.

Первая заметная проблема-отсутствие оперативности. Мы не можем знать, когда запускается финализатор, так как сбор мусора может произойти в любое время.

Само по себе это не проблема, потому что финализатор все равно выполняется, рано или поздно. Однако системные ресурсы не безграничны. Таким образом, у нас могут закончиться ресурсы до того, как произойдет очистка, что может привести к сбою системы.

Финализаторы также влияют на переносимость программы. Поскольку алгоритм сборки мусора зависит от реализации JVM, программа может очень хорошо работать в одной системе, но вести себя по-разному в другой.

Стоимость производительности-еще одна существенная проблема, связанная с финализаторами. В частности, JVM должна выполнять гораздо больше операций при создании и уничтожении объектов, содержащих непустой финализатор .

3.2. Демонстрация эффектов Финализаторов

Пришло время отложить теорию в сторону и увидеть эффекты финализаторов на практике.

Давайте определим новый класс с непустым финализатором:

Обратите внимание на метод finalize () – он просто выводит пустую строку на консоль. Если бы этот метод был полностью пуст, JVM обрабатывала бы объект так, как если бы у него не было финализатора. Поэтому нам нужно предоставить finalize() реализацию, которая в данном случае почти ничего не делает.

Внутри метода main в каждой итерации цикла for создается новый экземпляр CrashedFinalizable . Этот экземпляр не присваивается какой-либо переменной, следовательно, имеет право на сборку мусора.

Давайте добавим несколько операторов в строку, отмеченную //другим кодом , чтобы увидеть, сколько объектов существует в памяти во время выполнения:

Данные операторы обращаются к некоторым полям во внутренних классах JVM и выводят количество ссылок на объекты после каждого миллиона итераций.

Давайте запустим программу, выполнив метод main . Мы можем ожидать, что он будет работать бесконечно, но это не так. Через несколько минут мы должны увидеть сбой системы с ошибкой, подобной этой:

Похоже, сборщик мусора плохо справлялся со своей работой – количество объектов продолжало увеличиваться, пока система не рухнула.

Если бы мы удалили финализатор, количество ссылок обычно было бы равно 0, и программа продолжала бы работать вечно.

3.3. Объяснение

Чтобы понять, почему сборщик мусора не отбрасывал объекты должным образом, нам нужно посмотреть, как JVM работает внутри.

При создании объекта, также называемого референтом, который имеет финализатор, JVM создает сопутствующий ссылочный объект типа java.lang.ref.Finalizer . После того, как референт готов к сборке мусора, JVM помечает ссылочный объект как готовый к обработке и помещает его в очередь ссылок.

Мы можем получить доступ к этой очереди через статическое поле queue в классе java.lang.ref.Finalizer .

Тем временем специальный поток демона под названием Finalizer продолжает работать и ищет объекты в очереди ссылок. Когда он находит его, он удаляет ссылочный объект из очереди и вызывает финализатор для референта.

Во время следующего цикла сборки мусора референт будет отброшен – когда на него больше не будет ссылаться ссылочный объект.

Если поток продолжает создавать объекты с высокой скоростью, что и произошло в нашем примере, Финализатор поток не может идти в ногу. В конце концов, память не сможет хранить все объекты, и мы получим OutOfMemoryError .

Обратите внимание, что ситуация, когда объекты создаются со скоростью деформации, как показано в этом разделе, не часто случается в реальной жизни. Однако это демонстрирует важный момент – финализаторы очень дороги.

4. Пример Без финализатора

Давайте рассмотрим решение, обеспечивающее ту же функциональность, но без использования метода finalize () . Обратите внимание, что приведенный ниже пример-не единственный способ заменить финализаторы.

Вместо этого он используется для демонстрации важного момента: всегда есть варианты, которые помогают нам избежать финализаторов.

Вот объявление нашего нового класса:

Нетрудно заметить, что единственное различие между новым классом Closeable Resource и нашим предыдущим классом Finalizable заключается в реализации интерфейса AutoCloseable вместо определения финализатора.

Обратите внимание, что тело close метода Closeable Resource почти совпадает с телом финализатора в классе Finalizable .

Ниже приведен метод тестирования, который считывает входной файл и освобождает ресурс после завершения его работы:

В приведенном выше тесте экземпляр Закрываемого ресурса создается в блоке try инструкции try-with-resources, поэтому этот ресурс автоматически закрывается, когда блок try-with-resources завершает выполнение.

5. Заключение

В этом уроке мы сосредоточились на основной концепции Java – методе finalize . Это выглядит полезным на бумаге, но может иметь неприятные побочные эффекты во время выполнения. И, что еще более важно, всегда есть альтернативное решение для использования финализатора.

Один критический момент, который следует отметить, заключается в том, что завершать устарел, начиная с Java 9, и в конечном итоге будет удален.

Недавно меня пригласили в одну компанию на собеседование на должность Java-программиста. На собеседовании зашла речь о работе метода finalize. Я имел лишь поверхностное представление о работе этого метода и не смог дать достойного его описания интервьюверам. Поэтому после собеседования я должен был провести работу над ошибками и во всем разобраться.

Мои знания ограничивались тем, что метод finalize вызывается в момент, когда сборщик мусора начинает утилизировать объект. И я не совсем понимал для чего он служит. Я думал, что это что-то типа деструктора, в котором можно освобождать определенные ресурсы после того, как они больше не нужны, причем даже ресурсы, которые хранятся в других объектах, что не верно.

Так вот, первое, что требовалось понять — назначение.

Предназначен этот метод для автоматического освобождения системных ресурсов, занимаемых объектом, на котором будет данный метод вызван. Это кажется удобным, чтобы не помнить постоянно, например, что мы должны закрыть соединение с каким-то ресурсом, когда оно больше не требуется.

Не стоит полагаться на finalize для чистки данных. Во-первых, нет гарантии, что он будет вызван, т.к. где-то может остаться ссылка на объект. Во-вторых, нет гарантии на то, в какое время будет вызван метод. Это связано с тем, что после того, как объект становится доступным для сборки и, если в нем переопределен метод finalize, то он не вызывается сразу, а помещается в очередь, которая обрабатывается специально созданным для этого потоком. Стоит отметить, что в очередь на финализацию попадают только те объекты, в которых переопределен метод finalize.

Есть вероятность, что этот метод не будет вызван совсем. Это может произойти в момент, когда объект уже станет доступным для сборщика мусора и программа завершит свою работу.

Интересной особенностью метода является то, что он может снова сделать объект доступным, присвоив this какой-нибудь переменной, хотя так делать не рекомендуется, т.к. при восстановлении объекта, повторно finalize вызван не будет

Может случиться еще один редкий момент. У нас есть класс A, в котором реализован метод finalize. Мы создаем класс B extends A, в котором забываем про finalize. Объекты класса B содержат в себе много данных. Когда объекты классы B становятся ненужными, они попадут в очередь на финализацию и определенное время еще будут занимать память, вместо того, чтобы миновать этой очереди и сразу утилизироваться.

Еще одним недостатком является то, что надо помнить про вызов finalize-метода супер-класса, если мы переопределяем его. Разработчик не вызовет — никто не вызовет.

Исключения, брошенные в методе finalize, не обрабатываются потоком-финализатором, т.е. данный стектрейс скорее всего нельзя будет отследить.

Для себя я сделал вывод, что пользоваться этим методом без особой надобности не стоит, а случаи этой особой надобности на моей двух-с-половиной-летней практике пока не встречались.

Лучше вместо finalize писать методы типа close в java.io и вызывать их в блоке finally. Недостатком является то, что разработкик должен помнить, что ресурс после использования нужно закрыть. На помощь тут нам пришла Java SE 7 со своими try-with-resources

Но ведь этот метод для чего-то есть. Где и как его можно использовать? Есть ли примеры использования?

Finalize можно использовать как последний шанс закрыть ресурс, но никогда как первая или единственная попытка. Т.е. в дополнение к тому, что клиент может вызвать, например, метод close на объекте, представляющем ресурс. А может и забыть. Тогда можно попытаться ему помочь. Так сделано, например, в классе FileInputStream.java:

Данный подход часто используется в библиотеках Java.

PS. Прошу не принимать написанное за чистую правду. Я написал лишь то, как я понял прочитанный материал. Приму с радостью любые дополнения, критику и исправления.

Если у вас есть какой-либо опыт интервью, вы могли заметить, что интервьюеры, как правило, задают сложные вопросы, которые обычно берутся из базовых понятий. Один из таких вопросов, который чаще всего задают, заключается в различении между Final, Finally and Finalize на Java.

Что такое Java final?

С каждым из них последнее ключевое слово имеет разный эффект.

1. Переменная

Всякий раз, когда ключевое слово final в Java используется с переменной, полем или параметром, это означает, что после передачи ссылки или создания экземпляра его значение не может быть изменено во время выполнения программы. Если переменная без какого-либо значения была объявлена как final, тогда она называется пустой / неинициализированной конечной переменной и может быть инициализирована только через конструктор.

Давайте теперь посмотрим на пример.

2. Метод

В Java всякий раз, когда метод объявляется как final, он не может быть переопределен никаким дочерним классом на протяжении всего выполнения программы.

Давайте посмотрим на пример.

3. Класс

Когда класс объявляется как final, он не может наследоваться ни одним подклассом. Это происходит потому, что, как только класс объявлен как final, все члены-данные и методы, содержащиеся в классе, будут неявно объявлены как final.

Кроме того, как только класс объявлен как final, он больше не может быть объявлен как абстрактный. Другими словами, класс может быть одним из двух, конечным или абстрактным.

Давайте посмотрим на пример.

Блок Finally

В Java, Finally, является необязательным блоком, который используется для обработки исключений. Обычно ему предшествует блок try-catch. Блок finally используется для выполнения важного кода, такого как очистка ресурса или освобождение использования памяти и т. д.

Блок finally будет выполняться независимо от того, обрабатывается ли исключение или нет. Таким образом, упаковка кодов очистки в блок finally считается хорошей практикой. Вы также можете использовать его с блоком try без необходимости использовать блок catch вместе с ним.

Метод Finalize

Иногда, объекту может потребоваться выполнить какую-то важную задачу, такую как закрытие открытого соединения, освобождение ресурса и т. д., Прежде чем он будет уничтожен. Если эти задачи не будут выполнены, это может снизить эффективность программы.

Таким образом, сборщик мусора вызывает его для объектов, на которые больше нет ссылок и которые помечены для сбора мусора.

Этот метод объявлен как защищенный, чтобы ограничить его использование извне класса. Но вы можете переопределить его внутри класса, чтобы определить его свойства во время сборки мусора.

В заключение я добавил сравнение всех трех ключевых слов, которое поможет вам быстро определить основные различия.

Читайте также: