Як я намагався зрозуміти сенс методу finalize

Нещодавно мене запросили в одну компанію на співбесіду на посаду Java-програміста. На співбесіді зайшла мова про роботу методу finalize. Я мав лише поверхневе уявлення про роботу цього методу і не зміг дати гідного його опису інтерв'ювера. Тому після співбесіди я повинен був провести роботу над помилками у всьому розібратися.

Мої знання обмежувалися тим, що метод finalize викликається в момент, коли збирач сміття починає утилізувати об'єкт. І я не зовсім розумів для чого він служить. Я думав, що це щось типу деструктора, в якому можна звільняти певні ресурси після того, як вони більше не потрібні, причому навіть ресурси, які зберігаються в інших об'єктах, що не вірно.

Так от, перше, що потрібно зрозуміти - призначення.

Призначений цей метод для автоматичного звільнення системних ресурсів, займаних об'єктом, на якому буде даний метод викликаний. Це здається зручним, що б не пам'ятати постійно, наприклад, що ми повинні закрити з'єднання з якимось ресурсом, коли воно більше не потрібно.

Є ймовірність, що цей метод не буде викликаний зовсім. Це може статися в момент, коли об'єкт вже стане доступним для збирача сміття і програма завершить свою роботу.

Цікавою особливістю методу є те, що він може знову зробити об'єкт доступним, присвоївши this який-небудь змінної, хоча так робити не рекомендується, тому що при відновленні об'єкта, повторно finalize викликаний не буде

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

Ще одним недоліком є ​​те, що треба пам'ятати про виклик finalize-методу супер-класу, якщо ми переобумовленої його. Розробник не викличе - ніхто не викличе.

Винятки, кинуті в методі finalize, не обробляються потоком-фіналізатор, тобто даний стектрейс швидше за все не можна буде відстежити.

Є один спосіб бути впевненим, що finalize-методи були запущені для об'єктів, доступних для збирання: викликати System.runFinalization () або Runtime.getRuntime (). RunFinalization (). Вихід з методу здійснюється тільки тоді, коли всі доступні методи об'єктів для фіналізації будуть виконані

Для себе я зробив висновок, що користуватися цим методом без особливої ​​потреби не варто, а випадки цієї особливої ​​потреби на моїй двох-з-половиною-річній практиці поки не зустрічалися.

Краще замість finalize писати методи типу close в java.io і викликати їх в блоці finally. Недоліком є ​​те, що разработкік повинен пам'ятати, що ресурс після використання потрібно закрити. На допомогу тут нам прийшла Java SE 7 зі своїми try-with-resources

Але ж цей метод для чогось є. Де і як його можна використовувати? Чи є приклади використання?

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

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