На мій досвід, є одна і єдина причина для переосмислення Object.finalize()
, але це дуже вагома причина :
Розмістити код реєстрації помилок, finalize()
який повідомляє вас, якщо ви коли-небудь забудете посилатися close()
.
Статичний аналіз може зафіксувати лише упущення у тривіальних сценаріях використання, а попередження компілятора, згадані в іншій відповіді, мають таке спрощене уявлення про речі, що вам насправді потрібно вимкнути їх, щоб зробити щось нетривіальне. (У мене ввімкнено набагато більше попереджень, ніж будь-який інший програміст, про який я знаю або коли-небудь чув, але у мене немає тупого попередження.)
Фіналізація може здатися хорошим механізмом для того, щоб ресурси не залишалися нерозкритими, але більшість людей бачать це абсолютно неправильно: вони вважають це альтернативним механізмом резервного резервування, захисником "другого шансу", який автоматично врятує день, утилізуючи ресурси, які вони забули. Це мертве неправильно . Має бути лише один спосіб зробити будь-яку задану річ: або ти завжди все закриваєш, або остаточне завершення завжди все закриває. Але оскільки доопрацювання є ненадійним, доопрацювання не може бути.
Отже, існує така схема, яку я називаю Обов'язковим видаленням , і вона передбачає, що програміст відповідає за завжди явне закриття всього, що реалізує Closeable
або AutoCloseable
. (Оператор спробу використання ресурсів все ще вважається явним закриттям.) Звичайно, програміст може забути, тож саме тут вступає в дію фіналізація, але не як чарівна фея, яка в кінцевому підсумку магічно зробить все правильно: Якщо фіналізація виявиться що close()
не посилалося, це не такнамагатися викликати це саме тому, що з (з математичною визначеністю) з'являться орди програмістів n00b, які будуть покладатися на нього, щоб виконати ту роботу, яку вони занадто ліниві або занадто роздуми робили. Отже, при обов'язковому видаленні, коли доопрацювання виявить, що close()
не було викликано, воно записує яскраво-червоне повідомлення про помилку, повідомляючи програмісту великими великими великими літерами, щоб виправити його, його речі.
Як додаткову вигоду, ходить чутка, що "JVM проігнорує тривіальний метод finalize () (наприклад, той, який просто повертається, нічого не роблячи, як той, який визначений у класі Object)", тому при обов'язковому видаленні ви можете уникнути всієї завершення накладні витрати у всій вашій системі ( див. відповідь аліпа для отримання інформації про те, наскільки жахливі ці накладні витрати), кодуючи ваш finalize()
метод таким чином:
@Override
protected void finalize() throws Throwable
{
if( Global.DEBUG && !closed )
{
Log.Error( "FORGOT TO CLOSE THIS!" );
}
//super.finalize(); see alip's comment on why this should not be invoked.
}
Ідея цього полягає в тому, що Global.DEBUG
це static final
змінна, значення якої відоме під час компіляції, тож якщо саме false
тоді компілятор взагалі не видасть жодного коду для всього if
оператора, що зробить це тривіальним (порожнім) фіналізатором, що, у свою чергу означає, що до вашого класу поводиться так, ніби він не має фіналізатора. (У C # це було б зроблено з приємним #if DEBUG
блоком, але що ми можемо зробити, це java, де ми платимо очевидну простоту в коді з додатковими накладними витратами в мозку.)
Більше про обов'язкове знешкодження, з додатковою дискусією щодо утилізації ресурсів у крапці Net, тут: michael.gr: Обов’язкове утилізація проти гидоти "Утилізація-розпорядження"
finalize()
трохи заплутана. Якщо ви коли-небудь реалізовуєте це, переконайтеся, що він є безпечним для потоків стосовно всіх інших методів того ж об’єкта.