Accedi al campo privato di un altro oggetto nella stessa classe


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

Per favore dimentica il design. So che OOP specifica che gli oggetti privati ​​sono privati ​​della classe. La mia domanda è: perché l'OOP è stato progettato in modo tale che i campi privati ​​abbiano accesso a livello di classe e non a livello di oggetto ?


5
Credo che l'OP consideri l'oggetto "Person" passato a "someMethod" come un oggetto separato, e quindi il metodo non dovrebbe avere accesso ai suoi membri privati ​​... anche se è all'interno della classe "Person".
Inisheer

1
Alcune lingue non lo fanno (Newspeak per esempio). È improbabile che tu riceva una buona risposta sul perché. Otterrai risposte lavorando a ritroso da quanto è stato specificato.
Tom Hawtin - tackline

Il someMethodnon è valido. Non restituisce nulla. Deve essere void.
Nicolas Barbulesco

1
Se così non fosse, sarebbe molto difficile scrivere il costruttore di copie e l'operatore di assegnazione imo.
rozina

Risposte:


69

Sono anche un po 'curioso della risposta.

La risposta più soddisfacente che trovo proviene da Artemix in un altro post qui (sto rinominando la AClass con la classe Person): Perché avere modificatori di accesso a livello di classe invece che a livello di oggetto?

Il modificatore privato applica il principio di incapsulamento.

L'idea è che il "mondo esterno" non dovrebbe apportare modifiche ai processi interni della persona perché l'implementazione della persona può cambiare nel tempo (e dovresti cambiare l'intero mondo esterno per correggere le differenze nell'implementazione - il che è quasi impossibile).

Quando l'istanza di Person accede agli interni di un'altra istanza di Person, puoi essere certo che entrambe le istanze conoscono sempre i dettagli dell'implementazione di Person. Se la logica dei processi interni a Persona viene modificata, tutto ciò che devi fare è modificare il codice di Persona.

EDIT: Si prega di votare la risposta di Artemix. Lo sto solo copiando e incollando.


4
Questo è probabilmente il motivo. Ma questa è una cattiva idea . Questo incoraggia una cattiva pratica. Uno sviluppatore che accede a un campo di Person, nella classe Person, non deve conoscere l'implementazione dell'intera classe. La buona pratica è utilizzare la funzione di accesso, senza dover sapere quali operazioni esegue la funzione di accesso.
Nicolas Barbulesco

16
@NicolasBarbulesco Penso che la ragione fornita nella risposta sia valida. Supponiamo, ad esempio, di voler implementare il equals(Object)metodo in una classe Java per verificare l'uguaglianza di un Personoggetto con un'altra istanza di Person. Potresti voler consentire al mondo esterno di verificare se le due istanze sono uguali, ma potresti non voler esporre tutti i campi privati ​​della classe necessari per il controllo dell'uguaglianza al mondo esterno utilizzando metodi di accesso pubblico. Avere accesso a livello di classe ai privatecampi consente di implementare un tale metodo senza la necessità indotta di implementare tali metodi pubblici.
Malte Skoruppa

1
@MalteSkoruppa - Questo è un buon esempio (implementazione del metodo equals).
Nicolas Barbulesco

@MalteSkoruppa - Tuttavia, l'implementazione del metodo equalspotrebbe essere eseguita chiamando funzioni di accesso private.
Nicolas Barbulesco

@NicolasBarbulesco Sì, certo, ma il punto è che, se si utilizzano funzioni di accesso private o si accede direttamente a campi privati ​​per l'implementazione del metodo, privateè necessario garantire l'accesso a livello di classe. Sono d'accordo che usare gli accessori sia generalmente una buona abitudine, anche se in questo caso è soprattutto una questione di contesto e stile personale. Si noti che sia Joshua Bloch in Effective Java (elemento 8) che Tal Cohen in questo articolo del Dr. Dobbs accedono direttamente ai campi privati ​​nei loro elenchi di codici quando discutono su come implementarli equals.
Malte Skoruppa

17

Vedere le specifiche del linguaggio Java, sezione 6.6.1. Determinazione dell'accessibilità

Afferma

Altrimenti, se il membro o il costruttore viene dichiarato private, l'accesso è consentito se e solo se si verifica all'interno del corpo della classe di primo livello (§7.6) che racchiude la dichiarazione del membro o del costruttore.

Fare clic sul collegamento sopra per maggiori dettagli. Quindi la risposta è: perché James Gosling e gli altri autori di Java hanno deciso che fosse così.


17

Buona domanda. Sembra che il modificatore di accesso a livello di oggetto rafforzerebbe ulteriormente il principio di incapsulamento.

Ma in realtà è il contrario. Facciamo un esempio. Supponi di voler copiare in profondità un oggetto in un costruttore, se non puoi accedere ai membri privati ​​di quell'oggetto. Quindi l'unico modo possibile è aggiungere alcune funzioni di accesso pubbliche a tutti i membri privati. Questo renderà i tuoi oggetti nudi a tutte le altre parti del sistema.

Quindi l'incapsulamento non significa essere chiusi a tutto il resto del mondo. Significa essere selettivi su chi vuoi essere aperto.


2
Questa risposta deve essere votata! Altre risposte si limitano a ribadire la "regola", ma solo questa rivela davvero il motivo alla base della regola e raggiunge il punto.
mzoz

4
Ma non sarebbe meglio avere un oggetto responsabile della fornitura di copie di se stesso? Quindi, se hai bisogno di una copia profonda di un oggetto, non importa se sei un altro oggetto della stessa classe o un oggetto di una classe diversa: è lo stesso meccanismo, o.deepCopy()o qualsiasi altra cosa.
Dirtside

4

Funziona perché sei nella class Person- una classe può entrare nel proprio tipo di classe. Questo aiuta davvero quando vuoi scrivere un costruttore di copie, ad esempio:

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

O se vogliamo scrivere operator+e operator-per la nostra classe dei grandi numeri.


Questo è qualcosa di simile all'inserimento delle dipendenze. In cui puoi anche iniettare un oggetto di un'altra classe, dove non puoi accedere alla variabile private.
Nageswaran

Certo, se stai cercando di costruire una classe A da un oggetto di classe B, e B ha un componente privato, allora A deve essere dichiarato amico, o può vedere solo parti pubbliche [possibilmente protette, se A è derivato da B ].
Mats Petersson

In java e .net non esiste il concetto di amico. In questi casi, come gestirlo?
Nageswaran

1

Solo i miei 2 centesimi sulla questione del perché la semantica della visibilità privata in Java è a livello di classe piuttosto che a livello di oggetto.

Direi che la comodità sembra essere la chiave qui. Infatti, una visibilità privata a livello di oggetto avrebbe costretto ad esporre metodi ad altre classi (es. Nello stesso pacchetto) nello scenario illustrato dall'OP.

In verità non sono riuscito né a inventare né a trovare un esempio che dimostri che la visibilità a livello di classe-privato (come quella offerta da Java) crea problemi se paragonata alla visibilità a livello di oggetto-privato.

Detto questo, i linguaggi di programmazione con un sistema più dettagliato di politiche di visibilità possono offrire sia la visibilità degli oggetti a livello di oggetto che di classe.

Ad esempio Eiffel , offre l'esportazione selettiva: puoi esportare qualsiasi privilegio di classe in qualsiasi classe di tua scelta, da {NONE} (oggetto privato) a {ANY} (l'equivalente di pubblico, e anche l'impostazione predefinita), a {PERSON} (class-private, vedi l'esempio dell'OP), a gruppi specifici di classi {PERSON, BANK}.

È anche interessante notare che in Eiffel non è necessario rendere privato un attributo e scrivere un getter per impedire ad altre classi di assegnargli. Gli attributi pubblici in Eiffel sono accessibili per impostazione predefinita in modalità di sola lettura, quindi non è necessario un getter solo per restituire il loro valore.

Ovviamente hai ancora bisogno di un setter per impostare un attributo, ma puoi nasconderlo definendolo come "assegnatore" per quell'attributo. Ciò consente, se lo si desidera, di utilizzare l'operatore di assegnazione più conveniente invece dell'invocazione del setter.


0

Perché il private modificatore di accesso lo rende visibile solo all'interno della classe . Questo metodo è ancora IN classe .


La mia domanda è perché è progettato come "all'interno della classe" ma perché non come "solo all'interno dell'oggetto"?
Nageswaran

Perché è così che è fatto java.
darijan,

E perché Java ha fatto Java in questo modo?
Nageswaran

Java non ce l'ha fatta, i creatori di Java l'hanno fatto. Perché? Perché spaccano!
darijan

1
I creatori di Java non lo faranno senza alcun motivo e ci deve essere qualche ragione per farlo; Chiedo il motivo
Nageswaran

0

il privatecampo è accessibile nella classe / oggetto in cui il campo è dichiarato. È privato per altre classi / oggetti al di fuori di quello in cui si trova.


-1

La prima cosa che dobbiamo capire è che tutto ciò che dobbiamo fare è seguire i principi oops, quindi l'incapsulamento è dire che avvolgere i dati all'interno del pacchetto (cioè la classe) e quindi rappresentare tutti i dati come Object e di facile accesso. quindi, se rendiamo il campo non privato, allora vi si accede individualmente. e si traduce in un cattivo paratice.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.