Accéder au champ privé d'un autre objet de la même classe

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

Veuillez oublier le design. Je sais que la POO spécifie que les objets privés sont privés pour la classe. Ma question est la suivante: pourquoi la POO a-t-elle été conçue de telle sorte que les champs privés aient un accès au niveau de la classe et non un accès au niveau de l'objet ?

Nageswaran
la source
5
Je crois que l'OP considère l'objet "Person" passé à "someMethod" comme un objet séparé, et par conséquent la méthode ne devrait pas avoir accès à ses membres privés ... même si c'est dans la classe "Person".
Inisheer
1
Certaines langues ne le font pas (Newspeak par exemple). Vous n'obtiendrez probablement pas une bonne réponse quant à la raison. Vous obtiendrez des réponses à rebours à partir de ce qui a été spécifié.
Tom Hawtin - tackline
Le someMethodn'est pas valide. Cela ne renvoie rien. Ça doit être void.
Nicolas Barbulesco
1
Si ce n'était pas le cas, il serait très difficile d'écrire le constructeur de copie et l'opérateur d'affectation imo.
rozina

Réponses:

66

Je suis également un peu curieux de connaître la réponse.

La réponse la plus satisfaisante que je trouve vient d'Artemix dans un autre article ici (je renomme l'AClass avec la classe Person): Pourquoi avoir des modificateurs d'accès au niveau de la classe au lieu du niveau de l'objet?

Le modificateur privé applique le principe d'encapsulation.

L'idée est que le `` monde extérieur '' ne devrait pas apporter de modifications aux processus internes de la personne car la mise en œuvre de la personne peut changer avec le temps (et vous devrez changer tout le monde extérieur pour corriger les différences de mise en œuvre - ce qui est presque impossible).

Lorsque l'instance de Person accède aux composants internes d'une autre instance de Person, vous pouvez être sûr que les deux instances connaissent toujours les détails de l'implémentation de Person. Si la logique des processus internes à Person est modifiée, tout ce que vous avez à faire est de changer le code de Person.

EDIT: Veuillez voter pour la réponse d'Artemix. Je fais juste un copier-coller.

Iwan Satria
la source
4
C'est probablement la raison. Mais c'est une mauvaise idée . Cela encourage les mauvaises pratiques. Un développeur accédant à un champ de Person, dans la classe Person, n'a pas besoin de connaître l'implémentation de la classe entière. La bonne pratique consiste à utiliser l'accesseur, sans avoir à connaître les opérations effectuées par l'accesseur.
Nicolas Barbulesco
16
@NicolasBarbulesco Je pense que la raison invoquée dans la réponse est solide. Disons par exemple que vous souhaitez implémenter la equals(Object)méthode dans une classe Java pour vérifier l'égalité d'un Personobjet avec une autre instance de Person. Vous souhaiterez peut-être permettre au monde extérieur de vérifier si les deux instances sont égales, mais vous ne souhaiterez peut-être pas exposer tous les champs privés de la classe nécessaires pour vérifier l'égalité avec le monde extérieur à l'aide des méthodes d'accès public. Avoir un accès de niveau classe aux privatechamps permet d'implémenter une telle méthode sans la nécessité induite d'implémenter de telles méthodes publiques.
Malte Skoruppa
1
@MalteSkoruppa - Ceci est un bon exemple (implémentation de la méthode equals).
Nicolas Barbulesco
@MalteSkoruppa - Cependant, l'implémentation de la méthode equalspeut être effectuée en appelant des accesseurs privés.
Nicolas Barbulesco
@NicolasBarbulesco Oui bien sûr, mais le fait est que, que vous utilisiez des accesseurs privés ou que vous accédiez directement aux champs privés pour implémenter la méthode, vous devez privateaccorder un accès au niveau de la classe. Je conviens que l'utilisation des accesseurs est généralement une bonne habitude, même si dans ce cas, c'est surtout une question de contexte et de style personnel. Notez que Joshua Bloch dans Effective Java (point 8) et Tal Cohen dans cet article de Dr. Dobbs accèdent directement aux champs privés dans leurs listes de codes lorsqu'ils discutent de la mise en œuvre equals.
Malte Skoruppa
17

Voir la spécification du langage Java, section 6.6.1. Déterminer l'accessibilité

Il est dit

Sinon, si le membre ou le constructeur est déclaré private, alors l'accès est autorisé si et seulement s'il se produit dans le corps de la classe de niveau supérieur (§7.6) qui renferme la déclaration du membre ou du constructeur.

Cliquez sur le lien ci-dessus pour plus de détails. Donc, la réponse est: parce que James Gosling et les autres auteurs de Java ont décidé qu'il en était ainsi.

jlordo
la source
15

Bonne question. Il semble que le modificateur d'accès au niveau de l'objet appliquerait encore plus le principe d'encapsulation.

Mais en fait, c'est l'inverse. Prenons un exemple. Supposons que vous souhaitiez copier en profondeur un objet dans un constructeur, si vous ne pouvez pas accéder aux membres privés de cet objet. Ensuite, le seul moyen possible est d'ajouter des accesseurs publics à tous les membres privés. Cela rendra vos objets nus à toutes les autres parties du système.

L'encapsulation ne signifie donc pas être fermé à tout le reste du monde. Cela signifie être sélectif à propos de qui vous voulez être ouvert.

Wei Qiu
la source
2
Cette réponse doit être votée! D'autres réponses ne font que reformuler la «règle», mais seule celle-ci révèle vraiment la raison derrière la règle et touche le point.
mzoz
4
Mais ne serait-il pas préférable de confier à un objet la responsabilité de fournir des copies de lui-même? Ensuite, si vous avez besoin d'une copie complète d'un objet, peu importe que vous soyez un autre objet de la même classe ou un objet d'une classe différente: c'est le même mécanisme, o.deepCopy()ou autre.
dirtside
4

Cela fonctionne parce que vous êtes dans class Person- une classe est autorisée à pénétrer dans son propre type de classe. Cela aide vraiment lorsque vous souhaitez écrire un constructeur de copie, par exemple:

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

Ou si nous voulons écrire operator+et operator-pour notre grande classe de nombres.

Mats Petersson
la source
C'est quelque chose de similaire à l'injection de dépendances. Dans lequel vous pouvez également injecter un objet d'une autre classe, où vous ne pouvez pas accéder à la variable privée.
Nageswaran
Bien sûr, si vous essayez de construire une classe A à partir d'un objet de classe B et que B a un composant privé, alors soit A doit être déclaré ami, soit ne peut voir que les parties publiques [éventuellement protégées, si A est dérivé de B ].
Mats Petersson
En java et .net, il n'y a pas de concept d'ami. Dans de tels cas, comment gérer cela?
Nageswaran
1

Juste mes 2 cents sur la question de savoir pourquoi la sémantique de la visibilité privée en Java est au niveau de la classe plutôt qu'au niveau de l'objet.

Je dirais que la commodité semble être la clé ici. En fait, une visibilité privée au niveau objet aurait obligé à exposer des méthodes à d'autres classes (par exemple dans le même package) dans le scénario illustré par l'OP.

En vérité, je n'ai pas été en mesure de concocter ni de trouver un exemple montrant que la visibilité au niveau de la classe privée (comme celle offerte par Java) crée des problèmes par rapport à la visibilité au niveau de l'objet privé.

Cela dit, les langages de programmation avec un système plus fin de politiques de visibilité peuvent offrir à la fois une visibilité des objets au niveau de l'objet et au niveau de la classe.

Par exemple Eiffel , propose une exportation sélective: vous pouvez exporter n'importe quelle caractéristique de classe vers n'importe quelle classe de votre choix, de {NONE} (object-private) à {ANY} (l'équivalent de public, et aussi la valeur par défaut), vers {PERSON} (class-private, voir l'exemple de l'OP), à des groupes spécifiques de classes {PERSON, BANK}.

Il est également intéressant de remarquer que dans Eiffel, vous n'avez pas besoin de rendre un attribut privé et d'écrire un getter pour empêcher d'autres classes de lui attribuer. Les attributs publics dans Eiffel sont par défaut accessibles en mode lecture seule, vous n'avez donc pas besoin d'un getter juste pour renvoyer leur valeur.

Bien sûr, vous avez toujours besoin d'un setter pour définir un attribut, mais vous pouvez le masquer en le définissant comme "assigner" pour cet attribut. Cela vous permet, si vous le souhaitez, d'utiliser l'opérateur d'affectation le plus pratique au lieu de l'invocation du setter.

Temp Agilist
la source
0

Parce que le private modificateur d'accès le rend visible uniquement dans la classe . Cette méthode est toujours dans la classe .

Darijan
la source
Ma question est pourquoi il est conçu comme "dans la classe" mais pourquoi pas comme "seulement dans l'objet"?
Nageswaran
Parce que c'est ainsi que Java est fait.
darijan le
Et pourquoi Java a-t-il fait comme ça?
Nageswaran
Java n'a pas réussi, les créateurs de Java l'ont fait. Pourquoi? Parce qu'ils basculent!
darijan le
Les créateurs Java ne le feront pas sans aucune raison, et il doit y avoir une raison pour le faire; Je demande la raison
Nageswaran
0

le privatechamp est accessible dans la classe / l'objet dans lequel le champ est déclaré. Il est privé pour les autres classes / objets en dehors de celui dans lequel il se trouve.

Ola
la source
-1

La première chose que nous devons comprendre ici est que tout ce que nous avons à faire est de suivre les principes oops donc l'encapsulation consiste à dire que les données enveloppent le package (c'est-à-dire la classe) et que toutes les données soient représentées sous forme d'objet et faciles d'accès. donc si nous rendons le champ non privé, il y accède individuellement. et il en résulte une mauvaise paratice.

Sachin Jadhav
la source