Питання У Java різниця між пакетом приватною, загальнодоступною, захищеною та приватною


У Java існують чіткі правила про те, коли використовувати кожен з модифікаторів доступу, а саме за замовчуванням (пакет приватний), public, protected і private, при створенні class і interface і справу з спадком?


2500
2017-10-18 19:53


походження


private ховається від інших класів всередині пакета. public розкриває клас за межами упаковки. protected є версією public обмежується лише підкласами. - Museful
@ Теннрірішін - ні; на відміну від C ++, в Java protected робить метод доступним і з усієї упаковки. Ця дурість у моделі visiblity Java порушує цілі protected. - Nicolas Barbulesco
@Nicolas Це доступно з усього пакету, з або без protected. Як доступ модифікатор, все, що protected робити це піддавати підкласам поза пакету. - Museful
@tennenrishin - ну, це те, що сказав Ніколас ... і ви просто повторюєте це зараз. Те, що ви спочатку говорили, було так protected- і я цитую - "це версія публіки, обмежена лише підкласами", яка не відповідає вашим власним входом, оскільки захищена також дозволяє отримати доступ через весь пакет (ergo, це не обмежити доступ до підкласів.) - luis.espinal
Я також погоджуюсь з Nicolas у тому, що захищений режим доступу в Java ідіотський. Що сталося, це те, що Java об'єднує горизонтальних (решітка) та вертикальних обмежувачів обмеження доступу. Обсяг за умовчанням - це обмеження горизонтальної / решітчастої структури, оскільки решітка є пакетом. Громадськість - це ще одне горизонтальне обмеження, де решітка є цілим світом. Приватні та (C + +) захищені вертикально. Було б краще, якщо б ми мали перехресний доступ, скажімо, protected-package для рідкісних випадків, коли ми це дійсно потребували, залишаючи protected щоб бути еквівалентною C ++ версії захищеної. - luis.espinal


Відповіді:


Офіційний підручник може бути корисним для вас.

            │ Клас │ Пакет │ Підклас ğ Підклас │ Світ
            │ │ │ (той же pkg) │ (diff pkg) │
──────────────┼───────────────────────────────┼───────── ──┼────────
громадськість │ + │ + │ + │ + │ +
──────────────┼───────────────────────────────┼───────── ──┼────────
захищений │ + │ + │ + │ + │
──────────────┼───────────────────────────────┼───────── ──┼────────
немає модифікатора │ + │ + │ + │ │
──────────────┼───────────────────────────────┼───────── ──┼────────
приватний │ + │ │ │ │

+: доступний
порожній: недоступний

4660
2017-10-18 19:57



Якщо ви намагаєтесь отримати доступ до захищеного методу або змінної екземпляра у тому самому класі, але на об'єкті, який не є вашим, як у випадку з .equals (Klass var), він буде працювати? - Jordan Medlock
Поля полів за умовчанням видно в підкласах, якщо підкласи знаходяться в тому ж пакеті, що їх батьківський клас. - Maksim Dmitriev
У версіях Java та JDK до 1.0.1 ви можете використовувати приватні та захищені разом, щоб створити ще одну форму захисту, яка обмежила б доступ до методів або змінних лише до підкласів даного класу. - Vitalii Fedorenko
Це дуже багато голосів за відповідь, яка не відповідає на питання, яке було коли чи варто використовувати кожну видимість (не те, що є наслідками). - Bohemian♦
@Bohemian - відповідь передбачає, що ви знаєте, що, коли це можливо, слід використовувати найменш доступний специфікатор доступу (або припускає, що ви прочитали повну відповідь, дотримуючись посилання, яке також дає цю пораду). - iheanyi


(Застереження: Я не програміст Java, я програміст Perl.Perl не має офіційної захисту, це, мабуть, тому я розумію проблему так добре :))

Приватно

Як ти думаєш, тільки клас в якій це оголошено, це можна побачити.

Пакет приватний

Може бути видно і використовується тільки пакет в якому було оголошено. Це за замовчуванням на Java (які деякі бачать як помилку).

Захищений

Пакет Private + можна побачити за підкласами або членом пакета.

Громадський

Кожен може це побачити.

Опубліковано

Видимий за межами коду, який я контролюю. (Хоча не синтаксис Java, це важливо для цієї дискусії).

C ++ визначає додатковий рівень, який називається "другом", і чим менше ви знаєте про це, тим краще.

Коли потрібно використовувати що? Вся ідея - інкапсуляція, щоб приховати інформацію. Наскільки це можливо, ви хочете приховати подробиці того, як щось робиться від ваших користувачів. Чому? Тому що тоді ви можете змінити їх пізніше і не порушувати когось когось. Це дозволяє вам оптимізувати, рефакторитировать, переробляти та виправляти помилки, не турбуючись про те, що хтось використовував цей код, який ви просто оновили.

Отже, правилом великого пальця є те, щоб зробити речі настільки ж видимими, як вони повинні бути. Почніть з приватних і тільки додавати більше видимості, коли це необхідно. Публікуйте лише те, що абсолютно необхідно знати користувачеві, кожна деталь, яку ви публікуєте, супроводжує вашу здатність переробляти систему.

Якщо ви хочете, щоб користувачі мали змогу налаштовувати поведінку, а не робити загальнодоступні внутрішні компоненти, то вони можуть краще відмітити їх, а потім зробити їх відкритим. Таким чином, вони можуть просто підключити новий об'єкт. Наприклад, якщо ви пишете програвач компакт-дисків і хочеш, щоб біт налаштовувався на "шукати інформацію про цей компакт-диск", а не робити ці методи загальнодоступними, ви поставили б цю функціональність у власний об'єкт і зробили лише ваш об'єкт getter / setter публічним . Таким чином, будучи жахливим щодо виявлення ваших кишок, заохочує добрий склад та відокремлення проблем

Особисто я дотримуюся лише "приватних" і "публічних". Багато OO мов тільки що. "Захищений" може бути зручним, але це дійсно чит. Якщо інтерфейс більше, ніж приватний, він знаходиться поза вашим контролем, і ви повинні шукати в коді іншого користувача, щоб знайти використання.

Саме тут іде ідея "опубліковано". Зміна інтерфейсу (його рефакторинг) вимагає, щоб ви знаходили весь код, який його використовує, і змінити його. Якщо інтерфейс є приватним, добре немає проблем. Якщо він захищений, вам слід шукати всі підкласи. Якщо він загальнодоступний, вам слід шукати весь код, який використовує ваш код. Іноді це можливо, наприклад, якщо ви працюєте над корпоративним кодом, який призначений лише для внутрішнього використання, неважливо, чи інтерфейс є загальнодоступним. Ви можете взяти весь код з корпоративного сховища. Але якщо інтерфейс "опубліковано", якщо код використовує його поза вашим контролем, то ви хочете. Ви повинні підтримувати цей інтерфейс або кодекс ризику. Навіть захищені інтерфейси можна вважати опублікованими (тому я не турбуюся захищеними).

Багато мов вважає, що ієрархічна сутність державних / захищених / приватних є надто обмеженим та не відповідає дійсності. З цією метою існує поняття a клас ознаки, але це ще одне шоу.


358
2017-10-18 21:17



друзі -> "Чим менше ви знаєте про це, тим краще" ---> Це дає вибіркову видимість, яка все ще перевершує конфіденційність пакетів. У C ++ вона має свої цілі, оскільки не всі функції можуть бути функціями членів, а друзі краще, ніж публікувати. Звичайно, існує небезпека зловживання злими розумом. - Sebastian Mach
Слід також зазначити, що "захищений" в C ++ має інше значення - захищений метод ефективно приватний, але його можна викликати з класу успадкування. (На відміну від Java, де він може бути викликаний будь-яким класом всередині одного пакунка.) - Rhys van der Waerden
@RhysvanderWaerden C # такий самий, як і C ++ в цьому аспекті. Я вважаю це досить дивним, що Java не дозволяє оголосити член, доступний для підкласу, але не весь пакет. Це якраз перевернуто до мене - пакет має ширший обсяг, ніж дитячий клас! - Konrad Morawski
@KonradMorawski IMHO пакет менший обсяг, ніж підклас. Якщо ви не оголосили свій клас фінал, користувачі повинні мати змогу підкласувати його - так захищена Java є частиною вашого опублікованого інтерфейсу. OTOH, пакунки неявно розробляються однією організацією: наприклад, com.mycompany.mypackage. Якщо ваш код оголошує себе в моєму пакеті, ви неявно оголошуєте себе частиною моєї організації, тому ми повинні спілкуватися. Таким чином, пакет публікується на меншу / простішу для охоплення аудиторії (люди моєї компанії), ніж підклас (люди, які розширюють мій об'єкт), і тому вважається нижчою видимістю. - Eponymous
friendце добре для визначення особливих відносин між класами. Це дозволяє відмінно інкапсулювати в багатьох випадках, коли використовується правильно. Наприклад, він може бути використаний привілейованим класом фабрики для введення внутрішніх залежностей у конструюваний тип. Вона має погане ім'я, тому що люди, які не дбають про правильне підтримання добре продуманої об'єктної моделі, можуть зловживати його, щоб полегшити їх навантаження. - Dennis


Ось краща версія таблиці. (Майбутнє доказ із стовпцем для модулів.)

Java Access Modifiers

Пояснення

  • А. приватний член є тільки доступна в межах того самого класу, що й оголошено.

  • Член з немає модифікатора доступу доступний лише в класах в одному пакеті.

  • А. захищений Член доступний для всіх класів у тій же упаковці і в межах підкласів в інших пакунках.

  • А. громадськість член доступний для всіх класів (якщо він не проживає в модуль який не експортує пакет, який він оголошений).


Який модифікатор вибрати?

Модифікатори доступу - це інструмент, який допоможе вам уникнути випадкового розбиття(*). Поставте запитання, чи маєте ви бажання, щоб цей учасник був внутрішнім для класу, пакета, ієрархії класів або взагалі не внутрішній, і відповідно вибрати рівень доступу.

Приклади:

  • Поле long internalCounter Слід, мабуть, бути приватним, оскільки це є змінним і деталізацією.
  • Клас, який повинен бути показаний лише на фабричному класі (в тій же упаковці), повинен мати конструктор, обмежений пакетом, оскільки не можна буде називати його безпосередньо ззовні пакету.
  • Внутрішній void beforeRender() Метод, який називається безпосередньо перед відтворенням і використовується як гачок у підкласах, повинен бути захищений.
  • А. void saveGame(File dst) метод, який викликається з коду GUI, повинен бути загальнодоступним.

(*) Що таке інкапсуляція?


245
2017-11-10 10:27





                | highest precedence <---------> lowest precedence
*———————————————+———————————————+———————————+———————————————+———————
 \ xCanBeSeenBy | this          | any class | this subclass | any
  \__________   | class         | in same   | in another    | class
             \  | nonsubbed     | package   | package       |    
Modifier of x \ |               |           |               |       
————————————————*———————————————+———————————+———————————————+———————
public          |              |          |              |      
————————————————+———————————————+———————————+———————————————+———————
protected       |              |          |              |   ✘   
————————————————+———————————————+———————————+———————————————+———————
package-private |               |           |               |
(no modifier)   |              |          |       ✘       |   ✘   
————————————————+———————————————+———————————+———————————————+———————
private         |              |     ✘     |       ✘       |   ✘    

165
2018-01-09 21:42



Варто ввести слова: "Захищений модифікатор робить об'єкт доступним в інших пакунках, тоді як за замовчуванням / без модифікаторів обмежує доступ до одного пакета" - vanguard69
@ vanguard69, the protected модифікатор робить позначене річ (клас, метод або поле) доступні для деякого іншого класу в деякому іншому пакеті тільки iff сказав, що інший клас є підкласом класу, де це protected- позначено річ оголошується. - Abdull
"не"? "цей підклас в іншому пакеті"? Ага Я думав, що знаю Java. - sehe
@AlexanderFarber ви оптимізували для певної конфігурації веб-переглядача? Це мій хром зараз і це є Firefox - sehe
Хм, давайте повернемося до моїх змін - Alexander Farber


Легке правило. Почніть із оголошення всім приватним. І тоді прогрес у напрямку громадськості виникає, коли потреби виникають, і конструкція цього вимагає.

Під час опитування учасників запитайте себе, чи ви висвітлюєте вибір представлення або вибір абстракції. Перше - це те, що ви хочете уникнути, оскільки воно позначатиме занадто багато залежностей від фактичного подання, а не від його спостережуваної поведінки.

Як правило, я намагаюся уникнути переоцінки реалізації методу шляхом підкласу; це дуже легко привернути логіку. Оголосіть абстрактні захищені методи, якщо ви маєте намір його переоцінити.

Також використовуйте анотацію @Override під час перевизначення, щоб усунути речі при рефакторингу.


131
2017-10-18 20:00



@RuchirBaronia, "world" = весь код у додатку, незалежно від того, де він знаходиться. - Andrejs


Це насправді набагато складніше, ніж прості сітки шоу. Сітка повідомляє вам, чи дозволено доступ, але що саме являє собою доступ? Крім того, рівні доступу взаємодіють із вкладеними класами та успадкуванням складними способами.

Також називається доступ за замовчуванням (вказаний за відсутності ключового слова) пакет-приватний. Виняток: в інтерфейсі немає модифікатора означає публічний доступ; Модифікатори, крім загальнодоступних, заборонені. Константи Enum завжди публічні.

Резюме

Чи дозволено доступ до учасника за допомогою цього специфікатора доступу?

  • Учасник є private: Тільки якщо член визначено в тому ж класі, що і код виклику.
  • Член пакет є приватним: тільки якщо код виклику знаходиться безпосередньо в пакеті, що входить до складу учасника.
  • Учасник є protected: Той самий пакет, або якщо член визначено в суперкласі класу, що містить викличний код.
  • Учасник є public: Так.

Які специфікації доступу застосовуються до

Локальні змінні та формальні параметри не можуть приймати специфікатори доступу. Оскільки вони за своєю суттю недоступні для зовнішнього вигляду відповідно до норм обсягу, вони фактично є приватними.

Тільки для класів у верхній області public і пакет-приватні дозволені. Цей вибір дизайну, імовірно, тому що protected і private було б зайвим на рівні пакета (немає спадщини пакетів).

Всі специфікатори доступу можливі у членів класу (конструктори, методи та статичні функції членів, вкладені класи).

Пов'язані: Доступність класу Java

Замовлення

Специфікатори доступу можна суворо замовляти

public> protected> package-private> private

це означає, що public забезпечує найбільший доступ, private найменший. Будь-яке посилання на приватного члена також діє для приватного учасника пакету; будь-яка посилання на пакет-приватний член діє на захищеного члена тощо. (Отримання доступу захищених учасників до інших класів у тій же упаковці вважалося помилкою.)

Примітки

  • Методи класу є дозволено користуватися приватними членами інших об'єктів одного класу. Точніше, метод класу C може отримати доступ до приватних членів C на об'єктах будь-якого підкласу C. Java не підтримує обмеження доступу до екземпляра лише класом. (Порівняйте із Scala, яка підтримує її private[this].)
  • Вам потрібен доступ до конструктора для побудови об'єкта. Таким чином, якщо всі конструктори є приватними, клас може бути побудований лише за допомогою коду, що живе в межах класу (зазвичай статичні фабричні методи або стаціонарні ініціалізатори змін). Аналогічно для приватних або захищених пакетів конструкторів.
    • Тільки приватні конструктори також означають, що клас не може бути підкласований ззовні, оскільки Java вимагає конструкторів підкласу, щоб неявно або явно викликати конструктора суперкласса. (Це може, однак, містити вкладене клас, яке підкласує його.)

Внутрішні класи

Ви також повинні враховувати вкладений області, такі як внутрішні класи. Приклад складності полягає в тому, що внутрішні класи мають члени, які самі можуть приймати модифікатори доступу. Таким чином, ви можете мати приватний внутрішній клас із загальнодоступним учасником; Чи може член мати доступ? (Див. Нижче.) Загальне правило полягає в тому, щоб розглянути обсяг і мислити рекурсивно, щоб побачити, чи можна отримати доступ до кожного рівня.

Однак це досить складно, а для повних деталей, зверніться до Специфікації Java Language. (Так, у минулому були помилки компілятора.)

Зважаючи на те, як вони взаємодіють, розгляньте цей приклад. Можна "витік" приватних внутрішніх класів; це, як правило, попередження:

class Test {
    public static void main(final String ... args) {
        System.out.println(Example.leakPrivateClass()); // OK
        Example.leakPrivateClass().secretMethod(); // error
    }
}

class Example {
    private static class NestedClass {
        public void secretMethod() {
            System.out.println("Hello");
        }
    }
    public static NestedClass leakPrivateClass() {
        return new NestedClass();
    }
}

Випуск компілятора:

Test.java:4: secretMethod() in Example.NestedClass is defined in an inaccessible class or interface
        Example.leakPrivateClass().secretMethod(); // error
                                  ^
1 error

Деякі пов'язані питання:


94
2017-09-13 07:38





Як правило:

  • приватний: клас охоплення.
  • за замовчуванням (або пакет-приватний): обсяг пакунків.
  • захищений: пакетний обсяг + дитина (наприклад, пакет, але ми можемо підкласувати його з різних пакетів). Захищений модифікатор завжди зберігає відносини "батько-дитина".
  • громадськість: скрізь

В результаті, якщо ми розділимо право доступу на три права:

  • (D) правильно (виклик із методу всередині одного класу).
  • (R) eference (викликати метод, використовуючи посилання на клас або через сигнал "точка").
  • (I) спадщину (через підкласування).

то ми маємо цю просту таблицю:

+—-———————————————+————————————+———————————+
|                 |    Same    | Different |
|                 |   Package  | Packages  |
+—————————————————+————————————+———————————+
| private         |   D        |           |
+—————————————————+————————————+———————————+
| package-private |            |           |
| (no modifier)   |   D R I    |           |
+—————————————————+————————————+———————————+
| protected       |   D R I    |       I   |
+—————————————————+————————————+———————————+
| public          |   D R I    |    R  I   |
+—————————————————+————————————+———————————+

63
2017-12-18 18:01





В дуже короткому

  • public: доступний звідусіль.
  • protected: доступний для класів однієї упаковки та підкласів, що знаходяться в будь-якому пакеті.
  • за замовчуванням (не вказано модифікатор): доступно для класів того ж пакунка.
  • private: доступний тільки в одному класі.

43
2017-10-27 17:49





Найбільш неправильно зрозумілий модифікатор доступу в Java є protected. Ми знаємо, що він схожий на модифікатор за замовчуванням, за одним винятком, в якому підкласи можуть його бачити. Але як? Ось приклад, який, сподіваюсь, роз'яснює незрозумілість:

  • Припустимо, що у нас є 2 класи; Father і Son, кожен у своєму пакеті:

    package fatherpackage;
    
    public class Father
    {
    
    }
    
    -------------------------------------------
    
    package sonpackage;
    
    public class Son extends Father
    {
    
    }
    
  • Додамо захищений метод foo() до Father.

    package fatherpackage;
    
    public class Father
    {
        protected void foo(){}
    }
    
  • Метод foo() можна викликати в 4 контекстах:

    1. Усередині класу, який знаходиться в тому ж пакеті, де foo() визначено (fatherpackage):

      package fatherpackage;
      
      public class SomeClass
      {
          public void someMethod(Father f, Son s)
          {
              f.foo();
              s.foo();
          }
      }
      
    2. Всередині підкласу, на поточному екземплярі через this або super:

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod()
          {
              this.foo();
              super.foo();
          }
      }
      
    3. На референції, тип якого однаковий клас:

      package fatherpackage;
      
      public class Father
      {
          public void fatherMethod(Father f)
          {
              f.foo(); // valid even if foo() is private
          }
      }
      
      -------------------------------------------
      
      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Son s)
          {
              s.foo();
          }
      }
      
    4. На посилання, тип якого є батьківським класом, і він є всередині пакет де foo() визначено (fatherpackage) [Це може бути включено всередині контексту немає. 1]:

      package fatherpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo();
          }
      }
      
  • Наведені нижче ситуації недійсні.

    1. На посилання, тип якого є батьківським класом, і він є назовні пакет де foo() визначено (fatherpackage):

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo(); // compilation error
          }
      }
      
    2. Не підклас всередині пакета підкласу (підклас успадковує захищені елементи від батьків і робить їх приватними для не підкласів):

      package sonpackage;
      
      public class SomeClass
      {
          public void someMethod(Son s) throws Exception
          {
              s.foo(); // compilation error
          }
      }
      

32
2017-11-15 20:06



Object#clone() є прикладом a protected член - Eng.Fouad
Яка різниця між виконанням super.foo() і перша недійсна ситуація f.foo()? - cst1992
@ cst1992 Це незрозуміло, але див. специфікацію мови Java 6.6.2: "Захищений елемент або конструктор об'єкта може бути доступним з-за меж пакунку, в якому він оголошується лише кодом, який відповідає за реалізацію цього об'єкта". З super.foo () посилання "super" є "безпосередньо відповідальним за реалізацію", але посилання "f" не є. Чому? Тому що ви можете бути на 100% впевнені, що "супер" має тип "батько", але не "f"; під час виконання це може бути інший підтип батька. Побачити docs.oracle.com/javase/specs/jls/se9/html/... - skomisa
Це освіжає читати відповідь від того, хто розуміє protected. На жаль, всі інші відповіді на цій сторінці визначають protected отримати трохи неправильно. - Dawood ibn Kareem


Приватно

  • Методи, змінні та конструктори

Методи, змінні та конструктори, які оголошуються приватними, доступні лише в оголошеному класі.

  • Клас та інтерфейс

Модифікатор приватного доступу є найбільш обмеженим рівнем доступу. Клас і інтерфейси не можуть бути приватними.

Примітка

Змінні, які оголошуються приватними, можуть бути доступними за межами класу, якщо в класі присутні загальнодоступні методи геттера. Змінні, методи та конструктори, які оголошуються захищеними в суперкласі, доступні лише підкласам в іншому пакеті або будь-якому класі в пакеті класу захищених членів.


Захищений

  • Клас та інтерфейс

Захищений модифікатор доступу не може застосовуватися до класу та інтерфейсів.

Методи поля можуть бути оголошені захищеними, однак методи та поля в інтерфейсі не можуть бути оголошені захищеними.

Примітка

Захищений доступ дає підкласу шанс використати допоміжний метод або змінну, одночасно запобігаючи спробам не пов'язаного класу використовувати його.


Громадський

Клас, метод, конструктор, інтерфейс і т.д., оголошені публічним, можуть бути доступними з будь-якого іншого класу. 

Тому поля, методи, блоки, заявлені всередині публічного класу, можуть бути доступними з будь-якого класу, що належить до Java Universe.

  • Різні пакети

Проте, якщо загальний клас, який ми намагаємось отримати, знаходиться в іншому пакеті, то публічний клас все ж потрібно імпортувати.

Через класову спадщину всі відкриті методи та змінні класу успадковуються його підкласами.


За замовчуванням немає ключового слова:

Модифікатор доступу за умовчанням означає, що ми не оголошуємо явно модифікатор доступу для класу, поля, методу тощо.

  • У межах тих же пакетів

Змінна або метод, оголошений без будь-якого модифікатора контролю доступу, доступний для будь-якого іншого класу в одному пакеті. Поля в інтерфейсі є неявно публічним статичним фіналом, і методи в інтерфейсі за замовчуванням є загальнодоступними.

Примітка

Ми не можемо переопределити статичні поля. Якщо ви намагаєтесь перевизначити його, то не відображається ніяких помилок але це непрацююче те, що ми крім.

Пов'язані відповіді

Посилання на посилання

http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html http://www.tutorialspoint.com/java/java_access_modifiers.htm 


24
2018-01-22 13:08