Может ли метод finalize() в Java не быть вызванным?

«Может ли метод finalize() в Java не быть вызванным?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Причины, по которым finalize() может не выполниться:

  1. Недетерминированность сборщика мусора (GC): JVM не гарантирует, когда будет запущен GC. Объект может никогда не быть собранным.
  2. Принудительное завершение программы: Вызов System.exit(), аварийное завершение процесса (kill -9), ошибка в самой JVM.
  3. Исключение в другом finalize(): Непойманное исключение, выброшенное в методе finalize() какого-либо объекта, может прервать процесс финализации для оставшихся объектов.
  4. Объект "воскрес" во время финализации: Если в методе finalize() объект снова становится достижимым (например, присваивается статическому полю), он не будет собран, и finalize() больше не вызовется для него.

Пример, демонстрирующий неопределенность:

public class FinalizeDemo {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("Finalize called for " + this);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new FinalizeDemo(); // Создаем объекты без ссылок
        }
        // Подсказка GC, но не гарантия вызова finalize()
        System.gc();
        System.runFinalization(); // Еще одна попытка, также без гарантий
        // Часто вывод в консоли пуст или содержит не все сообщения
    }
}

Best Practice: Используйте блоки try-with-resources или явный вызов методов close() для управления ресурсами (реализуя AutoCloseable).