Greifen Sie auf das private Feld eines anderen Objekts in derselben Klasse zu

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

Bitte vergessen Sie das Design. Ich weiß, dass OOP angibt, dass private Objekte für die Klasse privat sind. Meine Frage ist, warum OOP so konzipiert wurde, dass private Felder Zugriff auf Klassenebene und keinen Zugriff auf Objektebene haben .

Nageswaran
quelle
5
Ich glaube, das OP betrachtet das an "someMethod" übergebene "Person" -Objekt als separates Objekt, und daher sollte die Methode keinen Zugriff auf ihre privaten Mitglieder haben ... obwohl es sich in der "Person" -Klasse befindet.
Inisheer
1
Einige Sprachen tun dies nicht (z. B. Newspeak). Sie werden wahrscheinlich keine gute Antwort bekommen, warum. Sie erhalten Antworten, die rückwärts von dem arbeiten, was gerade angegeben wird.
Tom Hawtin - Tackline
Das someMethodist nicht gültig. Es gibt nichts zurück. Es muss sein void.
Nicolas Barbulesco
1
Wenn dies nicht der Fall wäre, wäre es sehr schwierig, den Kopierkonstruktor und den Zuweisungsoperator imo zu schreiben.
Rozina

Antworten:

64

Ich bin auch ein bisschen neugierig auf die Antwort.

Die befriedigendste Antwort, die ich finde, stammt von Artemix in einem anderen Beitrag hier (ich benenne die Klasse AClass in Person um): Warum haben Zugriffsmodifikatoren auf Klassenebene anstelle von Objekten auf Objektebene?

Der private Modifikator erzwingt das Kapselungsprinzip.

Die Idee ist, dass die 'Außenwelt' keine Änderungen an den internen Prozessen der Person vornehmen sollte, da sich die Implementierung der Person im Laufe der Zeit ändern kann (und Sie die gesamte Außenwelt ändern müssten, um die Unterschiede in der Implementierung zu beheben - was nahezu unmöglich ist).

Wenn die Instanz von Person auf Interna einer anderen Personeninstanz zugreift, können Sie sicher sein, dass beide Instanzen immer die Details der Implementierung von Person kennen. Wenn die Logik der internen Prozesse für Personen geändert wird, müssen Sie lediglich den Code für Personen ändern.

EDIT: Bitte stimmen Sie die Antwort von Artemix ab. Ich füge es nur ein.

Iwan Satria
quelle
4
Dies ist wahrscheinlich der Grund. Aber das ist eine schlechte Idee . Dies fördert schlechte Praktiken. Ein Entwickler, der auf ein Feld Personin der Klasse zugreift Person, muss nicht die Implementierung der gesamten Klasse kennen. Die bewährte Methode besteht darin, den Accessor zu verwenden, ohne wissen zu müssen, welche Vorgänge der Accessor ausführt.
Nicolas Barbulesco
16
@NicolasBarbulesco Ich denke, der Grund in der Antwort ist Ton. Angenommen, Sie möchten die equals(Object)Methode in einer Java-Klasse implementieren , um die Gleichheit eines PersonObjekts mit einer anderen Instanz von zu überprüfen Person. Möglicherweise möchten Sie der Außenwelt ermöglichen, zu überprüfen, ob die beiden Instanzen gleich sind, aber Sie möchten möglicherweise nicht alle privaten Felder der Klasse verfügbar machen, die zum Überprüfen der Gleichheit mit der Außenwelt mithilfe öffentlicher Zugriffsmethoden erforderlich sind. Der Zugriff auf privateFelder auf Klassenebene ermöglicht die Implementierung einer solchen Methode, ohne dass die Notwendigkeit besteht, solche öffentlichen Methoden zu implementieren.
Malte Skoruppa
1
@MalteSkoruppa - Dies ist ein gutes Beispiel (Implementierung der Methode equals).
Nicolas Barbulesco
@MalteSkoruppa - Die Implementierung der Methode equalskann jedoch durch Aufrufen privater Accessoren erfolgen.
Nicolas Barbulesco
@NicolasBarbulesco Ja, natürlich, aber der Punkt ist, ob Sie private Accessoren verwenden oder direkt auf private Felder zugreifen, um die Methode zu implementieren, privatemuss Zugriff auf Klassenebene gewähren. Ich stimme zu, dass die Verwendung von Accessoren im Allgemeinen eine gute Angewohnheit ist, obwohl es in diesem Fall hauptsächlich um den Kontext und den persönlichen Stil geht. Beachten Sie, dass sowohl Joshua Bloch in Effective Java (Punkt 8) als auch Tal Cohen in diesem Artikel von Dr. Dobbs direkt auf private Felder in ihren Codelisten zugreifen, wenn sie über die Implementierung sprechen equals.
Malte Skoruppa
17

Siehe die Java-Sprachspezifikation, Abschnitt 6.6.1. Zugänglichkeit bestimmen

Es sagt aus

Andernfalls ist der privateZugriff nur dann zulässig , wenn das Mitglied oder der Konstruktor deklariert ist , wenn er innerhalb des Körpers der Klasse der obersten Ebene (§7.6) erfolgt, der die Deklaration des Mitglieds oder Konstruktors enthält.

Klicken Sie auf den Link oben, um weitere Informationen zu erhalten. Die Antwort lautet also: Weil James Gosling und die anderen Autoren von Java beschlossen haben, dass dies so ist.

jlordo
quelle
15

Gute Frage. Es scheint, dass der Zugriffsmodifikator auf Objektebene das Kapselungsprinzip noch weiter durchsetzen würde.

Aber eigentlich ist es umgekehrt. Nehmen wir ein Beispiel. Angenommen, Sie möchten ein Objekt in einem Konstruktor tief kopieren, wenn Sie nicht auf die privaten Mitglieder dieses Objekts zugreifen können. Dann besteht die einzig mögliche Möglichkeit darin, allen privaten Mitgliedern einige öffentliche Accessoren hinzuzufügen. Dadurch werden Ihre Objekte für alle anderen Teile des Systems nackt .

Kapselung bedeutet also nicht, für den Rest der Welt geschlossen zu sein. Es bedeutet, selektiv zu sein, für wen Sie offen sein möchten.

Wei Qiu
quelle
2
Diese Antwort muss abgestimmt werden! Andere Antworten geben nur die 'Regel' wieder, aber nur diese enthüllt wirklich den Grund für die Regel und trifft den Punkt.
Mzoz
4
Aber wäre es nicht besser, wenn ein Objekt für die Bereitstellung von Kopien von sich selbst verantwortlich wäre? Wenn Sie dann eine tiefe Kopie eines Objekts benötigen, spielt es keine Rolle, ob Sie ein anderes Objekt derselben Klasse oder ein Objekt einer anderen Klasse sind: Es ist der gleiche Mechanismus o.deepCopy()oder was auch immer.
Dirtside
4

Dies funktioniert, weil Sie sich in der class PersonKlasse befinden. Eine Klasse darf in ihren eigenen Klassentyp stecken. Dies ist sehr hilfreich, wenn Sie einen Kopierkonstruktor schreiben möchten, zum Beispiel:

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

Oder wenn wir schreiben wollen operator+und operator-für unsere große Zahlenklasse.

Mats Petersson
quelle
Dies ähnelt der Abhängigkeitsinjektion. In das Sie auch das Objekt einer anderen Klasse einfügen können, wo Sie nicht auf die private Variable zugreifen können.
Nageswaran
Sicher, wenn Sie versuchen, eine Klasse A aus einem Objekt der Klasse B zu erstellen, und B eine private Komponente hat, muss entweder A als Freund deklariert werden oder es können nur öffentliche Teile angezeigt werden [möglicherweise geschützt, wenn A von B abgeleitet ist ].
Mats Petersson
In Java und .net gibt es kein Konzept von Freund. Wie geht man in solchen Fällen damit um?
Nageswaran
1

Nur meine 2 Cent auf die Frage, warum die Semantik der privaten Sichtbarkeit in Java eher auf Klassenebene als auf Objektebene ist.

Ich würde sagen, dass Bequemlichkeit hier der Schlüssel zu sein scheint. Tatsächlich hätte eine private Sichtbarkeit auf Objektebene in dem vom OP dargestellten Szenario gezwungen, Methoden anderen Klassen (z. B. im selben Paket) auszusetzen.

In Wahrheit konnte ich weder ein Beispiel finden, das zeigt, dass die Sichtbarkeit auf klassenprivater Ebene (wie sie von Java angeboten wird) im Vergleich zur Sichtbarkeit auf objektprivater Ebene Probleme verursacht.

Programmiersprachen mit einem feinkörnigeren System von Sichtbarkeitsrichtlinien können jedoch sowohl Objektsichtbarkeit auf Objektebene als auch auf Klassenebene bieten.

Zum Beispiel bietet Eiffel einen selektiven Export: Sie können jedes Klassenfeature in eine beliebige Klasse Ihrer Wahl exportieren, von {NONE} (objektprivat) über {ANY} (das Äquivalent von public und auch die Standardeinstellung) bis {PERSON} (klassenprivat, siehe Beispiel des OP) für bestimmte Klassengruppen {PERSON, BANK}.

Es ist auch interessant zu bemerken, dass Sie in Eiffel kein Attribut privat machen und keinen Getter schreiben müssen, um zu verhindern, dass andere Klassen ihm zuweisen. Öffentliche Attribute in Eiffel sind standardmäßig im schreibgeschützten Modus verfügbar, sodass Sie keinen Getter benötigen, um ihren Wert zurückzugeben.

Natürlich benötigen Sie noch einen Setter, um ein Attribut festzulegen, aber Sie können es ausblenden, indem Sie es als "Zuweiser" für dieses Attribut definieren. Auf diese Weise können Sie auf Wunsch den bequemeren Zuweisungsoperator anstelle des Setter-Aufrufs verwenden.

Temp Agilist
quelle
0

Da der private Zugriffsmodifikator ihn nur innerhalb der Klasse sichtbar macht . Diese Methode ist noch in der Klasse .

Darijan
quelle
Meine Frage ist, warum es wie "innerhalb der Klasse" gestaltet ist, aber warum nicht wie "nur innerhalb des Objekts"?
Nageswaran
Denn so wird Java gemacht.
Darijan
Und warum hat Java Java so gemacht?
Nageswaran
Java hat es nicht geschafft, Java-Entwickler haben es geschafft. Warum? Weil sie rocken!
Darijan
Java-Ersteller tun dies nicht ohne Grund, und es muss einen Grund dafür geben. Ich frage den Grund
Nageswaran
0

Auf das privateFeld kann in der Klasse / dem Objekt zugegriffen werden, in der das Feld deklariert ist. Es ist für andere Klassen / Objekte außerhalb der Klasse, in der es sich befindet, privat.

ola
quelle
-1

Das erste, was wir hier verstehen müssen, ist, dass wir nur den oops-Prinzipien folgen müssen, damit die Kapselung besagt, dass Daten innerhalb eines Pakets (dh einer Klasse) verpackt werden und dann alle Daten als Objekt dargestellt werden und leicht zugänglich sind. Wenn wir also das Feld als nicht privat festlegen, wird nicht einzeln darauf zugegriffen. und es führt zu schlechter Paratice.

Sachin Jadhav
quelle