Понятно, что вы просто сопротивляетесь удалению метода finalize()
. В конце концов, он делает некоторую полезную очистку. Вопрос в том, чем его заменить.
Создание элемента AutoCloseable
может помочь, хотя это работает, только если элемент используется в пределах одной лексической области. Это позволит вам использовать try-with-resources. Если элемент не используется в лексической области, например, если он подключен к нескольким структурам данных, вы не сможете использовать try-with-resources. Здесь вам может потребоваться выполнить некоторые действия по очистке после того, как элемент станет недоступным.
Предпочтительная замена для финализации - использовать что-то вроде WeakReference
. Нормальные ссылки - это "сильные" ссылки. Когда все сильные ссылки ушли, оставив только слабые ссылки, предмет становится «слабо доступным». Это ставит в очередь ссылку на очередь ссылок; по сути, это событие, которое говорит, что «предмет больше недоступен», и действие, которое необходимо предпринять при получении этого события, состоит в выполнении некоторого действия очистки.
Этот тип обработки ссылок может быть неудобным, поэтому существует другой механизм, называемый Cleaner
, который может быть проще в использовании.
То, что сделало финализацию удобной, заключается в том, что метод finalize()
находится на самом объекте, который должен быть собран. Среди проблем с финализацией является то, что это «воскрешает» объект, создавая новую сильную ссылку на него.
Уловка со ссылкой или более чистой обработкой заключается в том, что вам нужно отслеживать вещи, которые необходимо очистить, без сохранения ссылки на объект, с которым он связан. В вашем случае у вас есть DiskCacheItem
, который, очевидно, содержится в DiskCache
. Если экземпляр DiskCacheItem
собирается собирать мусор, вы хотите удалить его из DiskCache
. Трудно сказать из вашего кода, но похоже, что действие по очистке заключается в удалении объекта File
, который может быть связан с DiskCacheItem
. Если так, вот что нужно сделать:
Создайте экземпляр Cleaner
, который будет отвечать за выполнение действий по очистке.
Создайте класс состояния, который содержит очищаемый материал, в данном случае File
.
Когда к DiskCache
добавляется DiskCacheItem
, создайте экземпляр класса состояния и зарегистрируйте его в Cleaner, связав его с действием очистки. В этом случае действие очистки заключается в удалении файла. Это возвращает экземпляр Cleanable
.
Если в DiskCacheItem
есть явное действие «закрыть» или «удалить», вызовите его clean()
для соответствующего очищаемого объекта. Это немедленно вызовет действие очистки.
Когда-нибудь в будущем, если DiskCacheItem
не будет удален явно и все сильные ссылки на него будут удалены, он станет фантомно достижимым. Это заставит Cleaner вызывать действие очистки.
Это эффективно заменяет финализацию и метод finalize()
, хотя для этого вам придется немного перестроить структуры данных.
После всего этого, какой смысл заменять финализацию механизмом Cleaner / Cleanable? Во-первых, вы можете явно очистить Cleanable. Когда он в конце концов становится недоступным, это просто сбор мусора. Никакой дополнительной обработки не делается. С помощью finalization, даже если финализуемый объект уже был логически очищен, JVM все равно необходимо запустить метод finalize (). Во-вторых, для завершения требуется дополнительный проход GC, чтобы гарантировать, что объект не был «воскрешен». При обработке ссылок и Cleaner нет возможности «воскресить» объект. В-третьих, финализация хрупка, и трудно правильно реализовать метод finalize ().