Доступ к частному полю другого объекта в том же классе

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;
   }
}

Забудьте о дизайне. Я знаю, что ООП указывает, что частные объекты являются частными для класса. У меня вопрос: почему ООП было разработано таким образом, чтобы частные поля имели доступ на уровне класса, а не на уровне объекта ?

Нагесваран
источник
5
Я считаю, что OP считает, что объект "Person", переданный в "someMethod", является отдельным объектом, и поэтому метод не должен иметь доступа к своим частным членам ... даже если он находится в классе "Person".
Inisheer
1
Некоторые языки этого не делают (например, новояз). Вы вряд ли получите хороший ответ на вопрос, почему. Вы получите ответы в обратном направлении от того, что было указано.
Tom Hawtin - tackline
someMethodНе действует. Он ничего не возвращает. Так должно быть void.
Николас Барбулеско
1
Если бы это было не так, было бы очень сложно написать конструктор копирования и оператор присваивания imo.
rozina

Ответы:

69

Мне тоже немного любопытен ответ.

Наиболее удовлетворительный ответ, который я нашел, получен от Artemix в другом сообщении здесь (я переименовал AClass в класс Person): Почему модификаторы доступа на уровне класса вместо уровня объекта?

Модификатор private обеспечивает соблюдение принципа инкапсуляции.

Идея состоит в том, что «внешний мир» не должен вносить изменения во внутренние процессы Person, потому что реализация Person может меняться со временем (и вам придется изменить весь внешний мир, чтобы исправить различия в реализации - что почти невозможно).

Когда экземпляр Person обращается к внутренним компонентам другого экземпляра Person, вы можете быть уверены, что оба экземпляра всегда знают детали реализации Person. Если логика внутренних для Person процессов изменилась - все, что вам нужно сделать, это изменить код Person.

РЕДАКТИРОВАТЬ: Пожалуйста, проголосуйте за ответ Артемикса. Я просто копирую это.

Иван Сатрия
источник
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 решили, что это так.

Jlordo
источник
17

Хороший вопрос. Похоже, что модификатор доступа на уровне объекта еще больше усилит принцип инкапсуляции.

Но на самом деле все наоборот. Возьмем пример. Предположим, вы хотите глубоко скопировать объект в конструкторе, если у вас нет доступа к закрытым членам этого объекта. Тогда единственный возможный способ - добавить несколько открытых методов доступа ко всем закрытым членам. Это сделает ваши объекты открытыми для всех остальных частей системы.

Таким образом, инкапсуляция не означает закрытие для всего остального мира. Это означает избирательность в отношении того, кому вы хотите быть открытыми.

Вэй Цю
источник
2
За этот ответ нужно проголосовать! Другие ответы просто повторяют «правило», но только этот действительно раскрывает причину, стоящую за правилом, и попадает в точку.
mzoz
4
Но не лучше ли, чтобы объект отвечал за предоставление своих копий? Затем, если вам нужна глубокая копия объекта, не имеет значения, являетесь ли вы другим объектом того же класса или объектом другого класса: это тот же механизм o.deepCopy()или что-то еще.
dirtside 08
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 ].
Матс Петерссон
В java и .net нет понятия друга. В таких случаях как с этим справиться?
Nageswaran
1

Только мои 2 цента на вопрос, почему семантика частной видимости в Java - это уровень класса, а не уровня объекта.

Я бы сказал, что ключевым моментом здесь является удобство . Фактически, частная видимость на уровне объекта вынудила бы предоставить методы другим классам (например, в том же пакете) в сценарии, показанном OP.

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

Тем не менее, языки программирования с более детальной системой политик видимости могут обеспечить видимость объектов как на уровне объекта, так и на уровне класса.

Например, Eiffel предлагает выборочный экспорт: вы можете экспортировать любую функцию класса в любой класс по вашему выбору, от {NONE} (объектно-частный) до {ANY} (эквивалент общедоступного, а также значение по умолчанию) до {PERSON} (class-private, см. пример OP), для определенных групп классов {PERSON, BANK}.

Также интересно отметить, что в Eiffel вам не нужно делать атрибут закрытым и писать геттер, чтобы предотвратить его присвоение другими классами. Публичные атрибуты в Eiffel по умолчанию доступны в режиме только для чтения, поэтому вам не нужен геттер только для возврата их значения.

Конечно, вам по-прежнему нужен установщик для установки атрибута, но вы можете скрыть его, определив его как «назначитель» для этого атрибута. Это позволяет вам, если хотите, использовать более удобный оператор присваивания вместо вызова установщика.

Темп Agilist
источник
0

Поскольку private модификатор доступа делает его видимым только внутри класса . Этот метод все еще находится в классе .

Дариджан
источник
У меня вопрос: почему он разработан как «внутри класса», а почему не как «только внутри объекта»?
Nageswaran
Потому что именно так делается java.
darijan
И почему java сделала именно такую ​​java?
Nageswaran
Java не сделала этого, создатели Java сделали. Зачем? Потому что они молодцы!
darijan
1
Создатели Java не сделают этого без всякой причины, и для этого должна быть какая-то причина; Я спрашиваю причину
Нагесваран
0

privateполе доступно в классе / объект , в котором объявлено поле. Он является частным для других классов / объектов за пределами того, в котором он находится.

Ола
источник
-1

Первое, что здесь мы должны понять, это все, что нам нужно сделать, это следовать принципам oops, поэтому инкапсуляция означает, что данные обертываются внутри пакета (т.е. класса), а затем все данные представляются как объект и легко доступны. поэтому, если мы сделаем поле не приватным, то доступ к нему будет осуществляться индивидуально. и это приводит к плохому параличу.

Сачин Джадхав
источник