finalize: устаревший механизм

Object.finalize() задумывался как последний шанс освободить внешний ресурс перед удалением объекта. На практике JVM не гарантирует ни время, ни сам факт вызова. Начиная с Java 9 механизм устарел, позднее помечен к удалению. В новом коде его использовать нельзя.

Почему он опасен

  • объект может долго ждать финализации и удерживать память;
  • медленный финализатор тормозит обработку остальных объектов;
  • исключение из finalize() игнорируется;
  • объект можно «воскресить», сохранив this в достижимом месте;
  • порядок финализации связанных объектов не определён;
  • финализация не заменяет транзакцию и не гарантирует освобождение файла, сокета или соединения.
// Правильно: ресурс закрывается явно.
class Report implements AutoCloseable {
    private final InputStream input;
 
    Report(Path path) throws IOException {
        input = Files.newInputStream(path);
    }
 
    @Override
    public void close() throws IOException {
        input.close();
    }
}
 
try (Report report = new Report(path)) {
    // работа с отчётом
}

Для ресурсов с явным жизненным циклом нужны AutoCloseable и try-with-resources. Cleaner и ссылки из java.lang.ref годятся только как страховочная сетка для редких низкоуровневых случаев: они тоже не дают своевременной гарантии.

Не путать

finalize, final и finally не связаны:

КонструкцияНазначение
finalize()устаревший callback перед возможным удалением объекта
finalзапрет повторного присваивания, переопределения или наследования
finallyблок очистки после try/catch

На собеседовании

Гарантирован ли вызов finalize()? Нет. Процесс может завершиться раньше, а JVM не обязана финализировать все объекты.

Можно ли закрывать JDBC-соединение в finalize()? Нет. Закрывать нужно явно, обычно через try-with-resources.

Чем заменить финализатор? Управляемым жизненным циклом (close), а при необходимости резервной очистки — Cleaner, понимая его ограничения.

Связано: Процесс сборки мусора, Виды ссылок в java.