Почему метод finalize () в java.lang.Object "защищен"? - PullRequest
35 голосов
/ 18 февраля 2010

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

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

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

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

Ответы [ 9 ]

24 голосов
/ 18 февраля 2010

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

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

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


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

23 голосов
/ 18 февраля 2010

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

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

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

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

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

Да

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

Разряд против финализации ()

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

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

3 голосов
/ 19 февраля 2010

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

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

3 голосов
/ 18 февраля 2010

Проверьте эту ссылку , которая обсуждает это.

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

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

2 голосов
/ 18 февраля 2010

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

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

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

1 голос
/ 06 мая 2012

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

1 голос
/ 18 февраля 2010

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

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

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

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

1 голос
/ 18 февраля 2010

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

...