Почему метод finalize() в java.lang.Object "защищен"?
Из любопытства
Почему модификатор доступа к методу finalize()
создается как protected
. Почему это не может быть public
? Может ли кто-нибудь объяснить мне какую-то конкретную причину?
Кроме того, я узнал, что метод finalize()
вызывается только один раз. Если я дважды назову его в своей программе, что происходит? Может ли сборщик мусора повторить это?
private void dummyCall() {
try {
finalize();
finalize();
} catch (Throwable e) {
e.printStackTrace();//NOT REACHES EXCEPTION
}
}
Ответы
Ответ 1
Я отвечу на ваш вопрос другим вопросом:
Почему метод finalize
не должен быть защищен?
В общем, вы должны стараться держать все как можно более приватным. Это инкапсуляция. В противном случае вы можете сделать все public
. finalize
не может быть private
(поскольку производные классы должны иметь доступ к нему, чтобы иметь возможность переопределить его), поэтому он должен быть по крайней мере protected
, но зачем выдавать больше доступа, когда это нежелательно?
Прочитав свой комментарий более внимательно, я предполагаю, что теперь вижу ваш главный момент. Я думаю, что ваш смысл состоит в том, что все происходит от java.lang.Object
и, следовательно, обращается к его членам protected
, для него это не имеет никакого значения (или любой метод в java.lang.Object
, если на то пошло), как public
, в отличие от protected
. Лично я считаю это ошибкой дизайна на Java. Это действительно исправлено в С#. Проблема не в том, почему finalize
защищен. Это нормально. Реальная проблема заключается в том, что вы не должны иметь возможность вызывать защищенные методы в базовом классе через ссылку на объект типа базового класса. У Эрика Липперта есть запись в которой обсуждается, почему разрешение такого доступа к защищенным членам - это плохая идея, которая подробнее о переполнении стека в этом вопросе.
Ответ 2
Почему метод finalize() модификатор выполнен как защищенный. Зачем не может быть общедоступным?
Он не является общедоступным, потому что он не должен вызываться кем-либо, кроме JVM. Однако он должен быть защищен, чтобы его можно было переопределить подклассами, которым необходимо определить поведение для него.
Если я назову его дважды в своей программе, внутренне, что происходит?
Вы можете назвать все, что хотите, его просто метод в конце концов. Однако, как и t20, он имеет особое значение для JVM
Будет ли сборщик мусора снова?
Да
Ответ 3
- finalize предназначен для вызова только gc и, как таковой, не требует открытого доступа
- finalize гарантируется, что gc будет вызываться только один раз , и сам вызов нарушит эту гарантию, поскольку gc не знает об этом.
- Любой класс переопределения может сделать окончательную публикацию, что, по моему мнению, плохо по вышеуказанным причинам.
- finalize не должен содержать много кода, так как любое исключение, созданное завершением, может убить поток финализатора gc.
Повторите попытку finalize()
- Управление собственными ресурсами или любым ресурсом, который требует вызова функции dispose() или close(), может вызвать затруднения в обнаружении ошибок, поскольку они будут выпущены только тогда, когда у jvm закончится нехватка памяти, вы должны освободить ресурсы вручную. Finalize следует использовать только для отладки утечек ресурсов или для случаев, когда управление ресурсами вручную слишком много.
- finalize будет вызываться в дополнительном потоке gc и может вызвать проблемы с блокировкой ресурсов и т.д.
- ссылочные классы, такие как WeakReference и ReferenceQueue, являются альтернативным (довольно сложным) способом борьбы с очисткой и могут иметь те же проблемы, что и finalize() для собственных ресурсов.
Опасайтесь ошибок в приведенных выше утверждениях, я немного устал: -)
Ответ 4
Просмотрите эту ссылку, в которой обсуждается это.
В принципе, для него было бы наиболее целесообразно быть private
, поскольку его следует вызывать только JVM (сборщик мусора). Но чтобы позволить подклассу вызывать родительский метод finalize()
как часть его finalize()
, он должен быть protected
.
(Изменить). И просто общая осторожность - использование метода finalize() обычно обескураживается, поскольку нет способа гарантировать, что он когда-либо будет вызван. Хотя это не означает, что вы у меня никогда не будет возможности использовать его - это просто редко.)
Ответ 5
Часть о finalize()
, вызываемая только один раз, применяется только к вызовам из GC. Вы можете представить, что объект имеет скрытый флаг "finalize()
был вызван GC", а GC проверяет этот флаг, чтобы знать, что делать с объектом. Флаг никак не влияет на ваши собственные вызовы ручной работы на finalize()
.
В завершение прочитайте эту статью от Hans Boehm (который хорошо известен своей работой по сборке мусора). Это является открытием для окончательной доработки; в частности, Бем объясняет, почему финализация обязательно асинхронна. Следствием является то, что, хотя финализация является мощным инструментом, она редко является правильным инструментом для заданий.
Ответ 6
Это не public
(или доступ по умолчанию), поскольку он должен был вызываться JVM внутри, когда объект собирает мусор - он не должен быть вызван ничем другим. И это не private
, потому что это должно быть переопределено, и вы не можете переопределить частные методы.
Если я назову его дважды в своей программе, внутренне, что происходит? Будет ли сборщик мусора вызовет это снова?
Наверное, да, но трудно представить себе сценарий, где это будет иметь какой-то смысл - точка finalize()
- это очистка, когда объект мусор собирается. И это даже не так хорошо, поэтому на самом деле вы должны избегать всего, а не экспериментировать.
Ответ 7
finalize() используется только JVM для очистки ресурсов при сборке объекта. Для класса разумно определить, какие действия следует предпринять при сборе, для чего ему может потребоваться доступ к super.finalize(). Для внешнего процесса на самом деле не имеет смысла вызывать finalize(), поскольку внешний процесс не имеет контроля над тем, когда объект собран.
Ответ 8
Кроме того, я узнал, что finalize() метод вызывается только один раз. Если я позвоню он дважды в моей программе, внутренне что происходит?
Вероятно, вы спрашиваете об этом под впечатлением от деструкторов С++ ~. В java finalize() метод не делает никакой магии (например, очистки памяти). Он должен быть вызван сборщиком мусора. Но не наоборот.
Я рекомендую вам прочитать соответствующую главу в Joshua Bloch "Эффективная Java". В нем говорится, что использование финализаторов является плохой практикой и может вызвать проблемы с производительностью и другими проблемами, и есть только несколько случаев, когда они должны использоваться. Глава начинается со следующих слов:
Финализаторы непредсказуемы, часто опасным и вообще ненужным.
Ответ 9
Я думаю, что причина, по которой защищена finalize
, будет заключаться в том, что, возможно, она переопределяется некоторыми классами в JDK, а эти переопределенные методы вызывается JVM.