What is the difference between public, protected, package-private and private in Java?
В чем разница между общедоступным, защищенным, закрытым пакетом и private в Java?
Существуют ли в Java четкие правила относительно того, когда использовать каждый из модификаторов доступа, а именно модификатор по умолчанию (package private), public, protected и private, при создании class и interface и решении вопросов наследования?
Виден за пределами кода, которым я управляю. (Хотя это не синтаксис Java, это важно для данного обсуждения).
C ++ определяет дополнительный уровень, называемый "друг", и чем меньше вы знаете об этом, тем лучше.
Когда и что следует использовать? Вся идея заключается в инкапсуляции для сокрытия информации. Вы хотите максимально скрыть детали того, как что-то делается, от ваших пользователей. Почему? Потому что тогда вы сможете изменить их позже и не нарушать чей-либо код. Это позволяет вам оптимизировать, рефакторинговать, перепроектировать и исправлять ошибки, не беспокоясь о том, что кто-то использовал код, который вы только что переработали.
Итак, эмпирическое правило заключается в том, чтобы делать вещи видимыми только настолько, насколько они должны быть. Начните с private и добавляйте больше видимости только по мере необходимости. Публикуйте только то, что необходимо знать пользователю, каждая деталь, которую вы публикуете, ограничивает вашу способность перепроектировать систему.
Если вы хотите, чтобы пользователи могли настраивать поведение, а не делать внутренние компоненты общедоступными, чтобы они могли их переопределять, часто бывает лучшей идеей поместить эти внутренности в объект и сделать этот интерфейс общедоступным. Таким образом, они могут просто подключить новый объект. Например, если вы пишете проигрыватель компакт-дисков и хотите настроить бит "go find info about this CD", вместо того, чтобы делать эти методы общедоступными, вы бы поместили всю эту функциональность в его объект и сделали общедоступным только ваш способ получения / установки объекта. Таким образом, скупость на раскрытие своих возможностей способствует хорошему составлению и разделению проблем
Я придерживаюсь только "private" и "public". Во многих OO-языках есть именно это. "Protected" может быть удобным, но это обман. Как только интерфейс становится более чем приватным, он оказывается вне вашего контроля, и вам приходится искать применение в коде других людей.
Именно здесь возникает идея "опубликованного". Изменение интерфейса (его рефакторинг) требует, чтобы вы нашли весь код, который его использует, и изменили его тоже. Если интерфейс приватный, то проблем нет. Если он защищен, вам нужно найти все свои подклассы. Если он общедоступный, вам нужно найти весь код, который использует ваш код. Иногда это возможно, например, если вы работаете над корпоративным кодом, предназначенным только для внутреннего использования, не имеет значения, является ли интерфейс общедоступным. Вы можете получить весь код из корпоративного репозитория. Но если интерфейс "опубликован", если есть код, использующий его вне вашего контроля, тогда вы закрыты. Вы должны поддерживать этот интерфейс или рискуете взломать код. Даже защищенные интерфейсы можно считать опубликованными (вот почему я не заморачиваюсь с protected).
Многие языки считают иерархическую природу public / protected / private слишком ограниченной и не соответствующей реальности. С этой целью существует концепция класса признаков, но это уже другое шоу.
Ответ 3
Вот улучшенная версия таблицы, которая также включает столбец для модулей.
Пояснения
Закрытый член (i) доступен только в том же классе, в котором он объявлен.
Член с модификатором доступа без (j) доступен только внутри классов в том же пакете.
Защищенный член (k) доступен во всех классах одного пакета и в подклассах других пакетов.
Открытый член (l) доступен для всех классов (если только он не находится в модуле, который не экспортирует пакет, в котором он объявлен).
Какой модификатор выбрать?
Модификаторы доступа - это инструмент, который поможет вам предотвратить случайное нарушение инкапсуляции(*). Спросите себя, хотите ли вы, чтобы элемент был чем-то внутренним по отношению к классу, пакету, иерархии классов или не был внутренним вообще, и выберите уровень доступа соответствующим образом.
Примеры:
Поле long internalCounter, вероятно, должно быть private, поскольку оно изменяемо и является деталью реализации.
Класс, экземпляр которого должен создаваться только в классе factory (в том же пакете), должен иметь конструктор с ограниченным пакетом, поскольку не должно быть возможности вызвать его напрямую из-за пределов пакета.
Внутренний void beforeRender() метод, вызываемый непосредственно перед рендерингом и используемый в качестве перехвата в подклассах, должен быть защищен.
void saveGame(File dst) Метод, который вызывается из кода GUI, должен быть общедоступным.