Доступ до приватного поля іншого об’єкта в тому ж класі


91
class Person 
{
   private BankAccount account;

   Person(BankAccount account)
   {
      this.account = account;
   }

   public Person someMethod(Person person)
   {
     //Why accessing private field is possible?

     BankAccount a = person.account;
   }
}

Будь ласка, забудьте про дизайн. Я знаю, що ООП визначає, що приватні об'єкти є приватними для класу. Моє питання полягає в тому, чому OOP був розроблений таким чином, щоб приватні поля мали доступ на рівні класу, а не на рівні об’єкта ?


5
Я вважаю, що OP вважає об'єкт "Person", переданий "someMethod", окремим об'єктом, і тому метод не повинен мати доступу до своїх приватних членів ... навіть незважаючи на те, що він знаходиться в класі "Person".
Inisheer

1
Деякі мови цього не роблять (наприклад, нова мова). Ви навряд чи отримаєте хорошу відповідь, чому. Ви отримаєте відповіді, працюючи в зворотному напрямку від того, що буде вказано.
Том Хоутін - таклін

someMethodЧи не діє. Це нічого не повертає. Це повинно бути void.
Ніколас Барбулеско,

1
Якби це було не так, було б дуже важко написати конструктор копіювання та оператор присвоєння imo.
rozina

Відповіді:


68

Мені також трохи цікаво відповісти.

Найзадовільніша відповідь, яку я знайшов, - це від Artemix в іншому дописі тут (я перейменовую AClass у клас Person): Чому модифікатори доступу на рівні класу замість рівня об’єкта?

Приватний модифікатор застосовує принцип інкапсуляції.

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

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

EDIT: Будь ласка, проголосуйте відповідь Artemix. Я просто копіюю його.


4
Це, мабуть, причина. Але це погана ідея . Це спонукає до поганої практики. Розробник, який звертається до поля Personв класі Person, не повинен знати реалізацію цілого класу. Хорошою практикою є використання аксесуара без необхідності знати, які операції він робить.
Ніколас Барбулеско,

16
@NicolasBarbulesco Я думаю, що причина, вказана у відповіді, є слушною. Скажімо, наприклад, що ви хочете реалізувати equals(Object)метод у класі Java для перевірки рівності Personоб'єкта з іншим екземпляром Person. Можливо, ви захочете дозволити зовнішньому світу перевіряти, чи обидва екземпляри рівні, але ви не хочете виставляти всі приватні поля класу, необхідні для перевірки рівності, зовнішньому світу за допомогою методів відкритого доступу. Наявність доступу до privateполів на рівні класу дозволяє реалізувати такий метод без необхідності застосовувати такі загальнодоступні методи.
Мальте Скоруппа

1
@MalteSkoruppa - Це хороший приклад (реалізація методу equals).
Ніколас Барбулеско,

@MalteSkoruppa - Однак реалізація методу equalsможе бути здійснена за допомогою виклику приватних доступу.
Ніколас Барбулеско,

@NicolasBarbulesco Так, звичайно, але справа в тому, чи використовуєте ви приватні засоби доступу або безпосередньо отримуєте доступ до приватних полів для реалізації методу, privateповинен надавати доступ на рівні класу. Я погоджуюся, що використання аксесуарів - це, як правило, гарна звичка, хоча в цьому випадку це здебільшого питання контексту та особистого стилю. Зверніть увагу, що і Джошуа Блох в Ефективній Java (пункт 8), і Тал Коен у цій статті доктора Доббса безпосередньо отримують доступ до приватних полів у своїх списках кодів, обговорюючи, як це реалізувати equals.
Мальте Скоруппа,

17

Див. Специфікацію мови Java, розділ 6.6.1. Визначення доступності

У ньому зазначено

В іншому випадку, якщо член або конструктор оголошено private, тоді доступ дозволений тоді і лише тоді, коли він відбувається в тілі класу верхнього рівня (§7.6), що включає декларацію члена або конструктора.

Клацніть на посилання вище, щоб отримати докладнішу інформацію. Тож відповідь така: Оскільки Джеймс Гослінг та інші автори Java вирішили, що це має бути саме так.


16

Хороше питання. Здається, модифікатор доступу на рівні об’єкта ще більше запровадить принцип інкапсуляції.

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

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


2
Цю відповідь потрібно проголосувати! Інші відповіді просто повторюють "правило", але лише цей насправді виявляє причину, що лежить в основі правила, і вражає суть справи.
mzoz

4
Але чи не було б краще, щоб об’єкт відповідав за надання своїх копій? Тоді, якщо вам потрібна глибока копія об’єкта, не має значення, чи є ви іншим об’єктом того самого класу чи об’єктом іншого класу: це той самий механізм o.deepCopy()чи що інше.
dirtside

4

Це працює, оскільки ви перебуваєте в class Personкласі - класу дозволено тикати всередину власного типу класу. Це дійсно допомагає, коли ви хочете написати конструктор копій, наприклад:

class A
{
   private:
      int x;
      int y;
   public:
      A(int a, int b) x(a), y(b) {}
      A(A a) { x = a.x; y = y.x; }
};

Або якщо ми хочемо писати operator+і operator-для нашого класу великих чисел.


Це щось схоже на введення залежності. У якому ви також можете ввести об'єкт іншого класу, де ви не можете отримати доступ до приватної змінної.
Nageswaran

Звичайно, якщо ви намагаєтеся побудувати клас A з об’єкта класу B, а B має приватний компонент, тоді або A потрібно оголосити другом, або ви можете бачити лише загальнодоступні частини [можливо захищені, якщо A походить від B ].
Mats Petersson,

У Java та .net немає поняття друг. У таких випадках, як з цим впоратися?
Нагесваран,

1

Лише мої 2 центи на питання, чому семантика приватної видимості в Java є рівнем класу, а не об’єктом.

Я б сказав, що тут, здається, зручність . Насправді, приватна видимість на рівні об'єкта змусила б піддавати методи іншим класам (наприклад, у тому самому пакеті) у сценарії, проілюстрованому OP.

По правді кажучи, я не зміг ні придумати, ні знайти приклад, що показує, що видимість на рівні класу-приватності (як, наприклад, пропонується Java) створює будь-які проблеми, якщо порівнювати з видимістю на рівні об'єкт-приват.

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

Наприклад, Ейфель пропонує вибірковий експорт: ви можете експортувати будь-яку функцію класу до будь-якого класу на ваш вибір, від {NONE} (об'єктно-приватний) до {ANY} (еквівалент загальнодоступного, а також за замовчуванням), до {PERSON} (клас-приват, див. приклад OP), для певних груп класів {PERSON, BANK}.

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

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


0

Оскільки private модифікатор доступу робить його видимим лише в межах класу . Цей метод все ще в класі .


Моє питання полягає в тому, чому він розроблений як "всередині класу", а чому не як "лише в об'єкті"?
Nageswaran

Бо так роблять java.
darijan

І чому java зробив Java таким?
Nageswaran,

Java не встигла, а творці Java. Чому? Бо вони розгойдуються!
darijan

Творці Java не роблять цього без будь-якої причини, і для цього повинні бути певні причини; Я запитую причину
Нагесваран

0

privateполе є в класі / об'єкт , в якому оголошено поле. Він є приватним для інших класів / об’єктів, крім того, в якому він знаходиться.


-1

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


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.