Почему метод finalize () в java.ленг.Объект "защищен"?

из любопытства,

почему finalize() модификатор доступа метода выполнен как protected. Почему этого не может быть?--3-->? Может кто-нибудь объяснить мне какую-то конкретную причину этого?

кроме того, я узнал, что finalize() метод вызывается только один раз. Если я назову это дважды в своей программе внутренне, что происходит? Сборщик мусора позвонит еще раз?

private void dummyCall() {
    try {
        finalize();
        finalize();
    } catch (Throwable e) {
        e.printStackTrace();//NOT REACHES EXCEPTION
    }
}

9 ответов


я отвечаю на ваш вопрос другим вопросом:

почему finalize метод не должен быть защищен?

в общем, вы должны стараться держать вещи как можно более конфиденциальными. Вот что такое инкапсуляция. В противном случае, вы могли бы сделать все public. finalize не может быть private (поскольку производные классы должны иметь доступ к нему, чтобы иметь возможность переопределить его), поэтому он должен быть по крайней мере protected но зачем выдавать больше доступ, когда это нежелательно?


после прочтения вашего комментария более внимательно, я думаю, что теперь я вижу вашу основную мысль. Я думаю, что ваша точка зрения, так как все происходит от java.lang.Object и, следовательно, получает доступ к его protected члены, это не имело бы никакого значения для него (или любого метода в java.lang.Object если на то пошло) должны быть public в противоположность protected. Лично я бы посчитал это недостатком дизайна на Java. Это действительно зафиксировано в C#. Проблема не в том, почему finalize защищен. Все нормально. Реальная проблема заключается в том, что вы не должны вызывать защищенные методы в базовом классе через ссылку на объект типа базового класса. У Эрика Липперта есть запись в блог обсуждение того, почему разрешение такого рода доступа к защищенным членам-плохая идея, которая подробнее о переполнении стека в этом вопросе.


почему доступ к методу finalize () модификатор выполнен защищенным. Почему? разве это не публично?

он не является общедоступным, потому что он не должен вызываться кем-либо, кроме JVM. Однако он должен быть защищен, чтобы его можно было переопределить подклассами, которым необходимо определить поведение для него.

Если я вызову его дважды в моей программе, что происходит внутри?

Вы можете назвать это все, что вы хотите, его просто в конце концов, метод. Однако, очень нравится public static void main(String [] args), Это имеет особое значение для JVM

будет ли сборщик мусора вызывать это опять?

да


  • finalize предназначен для вызова только gc и как таковой не требует открытого доступа
  • finalize гарантированно вызывается только один раз gc, называя его себя нарушит эту гарантию, так как gc не будет знать об этом.
  • любой переопределяющий класс может сделать finalize общедоступным, что я считаю плохим по вышеуказанным причинам
  • finalize не должен содержать много кода, так как любое исключение, вызванное finalize, может убить поток финализатора gc.

разглагольствовать против finalize ()

  • управление собственными ресурсами или любым ресурсом, который требует вызова dispose() или close (), может вызвать трудности с поиском ошибок, поскольку они будут выпущены только тогда, когда у jvm закончится память, вы должны освободить ресурсы вручную. Завершить работу следует использовать только для отладки утечек ресурсов или для случаев, когда управление ресурсами вручную-слишком много работы.
  • finalize будет вызван в дополнительный поток gc и может вызвать проблемы с блокировкой ресурсов и так далее.
  • ссылочные классы, такие как WeakReference и ReferenceQueue, являются альтернативным (довольно сложным) способом очистки и могут иметь те же проблемы, что и finalize() для собственных ресурсов.

остерегайтесь ошибок в приведенных выше утверждениях, я немного устал : -)


проверить этой ссылке что обсуждает это.

в принципе, было бы разумнее всего, чтобы это было private, поскольку он должен вызываться только JVM (сборщиком мусора). Но для того, чтобы позволить подклассу вызывать parent finalize() метод как часть его finalize(), должно быть protected.

(редактировать - и просто общее предостережение-использование метода finalize () обычно не рекомендуется, поскольку нет никакого способа гарантировать, что он когда-либо будет называемый. Хотя это не означает, что у вас никогда не будет возможности использовать его - это просто редкость.)


о finalize() вызов только один раз применяется только к вызовам из GC. Вы можете представить объект как имеющий скрытый флаг"finalize() был вызван GC", и GC проверяет этот флаг, чтобы знать, что делать с объектом. Флаг никоим образом не влияет на ваши собственные звонки ручной работы на finalize().

по завершении прочтите в этой статье от Ханса Бема (который известен своей работой по сбору мусора). Это откровение о завершение; в частности, Бем объясняет, почему завершение обязательно асинхронно. Следствием этого является то, что, хотя завершение является мощным инструментом, оно очень редко является правильным инструментом для данной работы.


- Это не public (или доступ по умолчанию), потому что он предназначен для вызова JVM внутренне, когда объект является собранным мусором - это не предназначен для вызова чем-либо еще. И это не private потому что он должен быть переопределен, и вы не можете переопределить частные методы.

Если я вызову его дважды в моей программе, что происходит внутри? Будет сборщик мусора назовет это опять?

вероятно, да, но это трудно представить себе сценарий, в котором это имело бы какой - либо смысл-точка finalize() выполнять очистку, когда объект является собранным мусором. И это даже не так хорошо, поэтому это действительно то, чего вы должны избегать, а не экспериментировать.


finalize () используется JVM только для очистки ресурсов при сборе объекта. Для класса разумно определить, какие действия следует предпринять для коллекции, для которой может потребоваться доступ к super.завершать.)( На самом деле для внешнего процесса нет смысла вызывать finalize(), так как внешний процесс не имеет контроля над тем, когда объект собирается.


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

вы, вероятно, спросите об этом под впечатлением деструкторов C++~. В java finalize () метод не делает никакой магии (например, очистка памяти). Его должен был вызвать сборщик мусора. Но не наоборот.

Я рекомендую вам прочитать корреспондентскую главу в "эффективной Java" Джошуа Блоха. Он говорит, что использование финализаторов-плохая практика и может вызвать проблемы с производительностью и другие проблемы, и есть только несколько случаев, когда они должны использоваться. Глава начинается следующими словами:--2-->

финализаторы непредсказуемы, часто опасно и вообще не нужно.


Я думаю, причина почему finalize защищено было бы, что, возможно, оно переопределено некоторыми классами в JDK, и эти переопределенные методы вызываются JVM.