Perché un membro privato è accessibile con un metodo statico?


25

Quello che segue è lo pseudo codice, l'ho provato in Java e PHP ed entrambi hanno funzionato:

class Test { 

    private int a = 5;

    public static function do_test(){
        var t = new Test();
        t.a = 1;
        print t.a // 1
    }

}

Test::do_test();

Perché puoi farlo nel paradigma OOP e a che cosa serve?


6
Perché non dovrebbe essere? In Java i membri privati ​​non sono privati ​​per istanza, ma piuttosto privati ​​per il file sorgente . Il primo uso che viene in mente è equalsquello di controllare i campi privati ​​di un'altra istanza. (Pubblicazione come commento, in quanto breve, e nulla sull'oop-ness di questo approccio)
Ordous

2
Nota che i metodi statici non hanno un this, quindi gli unici oggetti della loro stessa classe a cui possono arrivare sono quelli che creano loro stessi (o che vengono passati come parametro). Quindi se consideri questa una violazione dell'incapsulamento o di una falla di sicurezza, non è come se fosse una grande, e potrebbe non valere la pena collegarla.
Kilian Foth,

4
Non sono sicuro del motivo per cui questo è stato sottoposto a downgrade. La domanda potrebbe essere banale (ish), ma l'OP ha avuto il problema di testare il comportamento in due lingue prima di porlo. Questo è uno sforzo molto maggiore di quello che normalmente vediamo dai nuovi arrivati.
yannis,

1
@YannisRizos D'accordo, e in effetti non penso che la domanda sia banale. Ha implicazioni per seguire il "principio del privilegio minimo". Significa che le funzioni di supporto che non hanno bisogno di accedere agli interni di un'istanza dovrebbero essere definite in una classe separata , e viceversa quando viene seguita questa convenzione sapresti che ogni volta che esiste un metodo statico all'interno della stessa classe, accede allo stato interno.
Doval,

1
In effetti, quando ho chiesto ai miei colleghi tutti loro hanno detto che questo è impossibile. Ecco perché non pensavo che fosse banale
Ben

Risposte:


17

In Java, le variabili private sono visibili a tutta la classe. È possibile accedervi da metodi statici e da altre istanze della stessa classe.

Questo è, ad esempio, utile nei metodi di fabbrica . Un metodo factory di solito esegue le inizializzazioni su un oggetto così complesso che non si desidera lasciarle al codice dell'applicazione. Per eseguire l'inizializzazione, il metodo factory spesso richiede l'accesso agli interni di classe che non si desidera esporre. Essere in grado di accedere direttamente alle variabili private ti semplifica la vita.

Tuttavia, quando si desidera nascondere i dettagli di implementazione di una classe anche da metodi statici o da altre istanze di quella classe, è possibile seguire il modello di dati della classe privata . Metti tutte le variabili private di una classe in una classe interna privata e delega qualsiasi getter o setter a getter e setter di quella classe interna.

Un'altra opzione è quella di definire un'interfaccia per la classe che dichiari tutti i metodi pubblici della classe e quindi fare riferimento alla classe sotto quell'interfaccia ove possibile. Un riferimento al tipo di interfaccia non può essere utilizzato per accedere direttamente a qualsiasi cosa non dichiarata nell'interfaccia, indipendentemente da dove (tranne che con la riflessione, ovviamente). Quando si utilizza un linguaggio di programmazione orientato agli oggetti che non ha interfacce (come C ++, ad esempio), possono essere simulati con una classe base astratta ereditata dalla classe effettiva.

interface ITest {
     public int getA();
}

class Test implements ITest { 

    private int a = 5;

    public int getA() { return a; } // implementation of method declared in interface

    public static void main(){
        ITest t = new Test();
        t.a = 1; // syntax error: Interface ITest has no "a"
        System.out.println(t.getA()); // calls Test.getA, visible because ITest declares it
    }

}

Riesci a pensare a una situazione in cui il modello di dati di classe privata è utile? Personalmente utilizzo le classi interne solo nella GUI come configurazioni (Swing, ecc.) O classi interne statiche negli esercizi di codifica poiché non voglio che un esercizio comprenda più file sorgente.
Informato il

1
Nascondere gli interni di una classe da altre istanze toglie uno dei vantaggi che le classi hanno sulle interfacce senza ottenere nulla in cambio. Una soluzione più semplice e flessibile è usare semplicemente un'interfaccia.
Doval,

3

Alcuni linguaggi e framework di runtime (ad es. Java,. operazione. Altre lingue e framework sono più restrittivi al riguardo e non consentono l'accesso ai membri privati ​​di un'istanza se non tramite il codice in esecuzione su tale istanza . Entrambi i design presentano vantaggi e svantaggi.

Il più grande vantaggio di consentire a qualsiasi codice all'interno di una classe di accedere a membri privati ​​di qualsiasi istanza è che ci sono casi in cui quel livello di accesso è appropriato e che privatelavorare in questo modo elimina la necessità di avere un qualificatore di accesso diverso disponibile a tale scopo o altrimenti forza il codice per esporre i membri in modo più ampio di quanto sarebbe altrimenti ideale.

Un vantaggio di non consentire tale accesso (come nel caso del Microsoft Common Object Model (COM)) è che consente al codice esterno di trattare le classi come interfacce. Se una classe ImmutableMatrixcontiene un double[][]campo di supporto privato o protetto e se il codice all'interno della classe esamina l'array di supporto di altre istanze, non sarà possibile definire una classe non supportata da array (ad es ZeroMatrix. IdentityMatrix) Che il codice esterno potrebbe usare come an Immutable2dMatrix, senza che quella classe debba includere il campo di supporto. Se nulla all'interno Immutable2dMatrixutilizza membri privati ​​di qualsiasi istanza diversa da quella this, allora sarebbe possibile rinominare la classe ImmutableArrayBackedMatrixe definire una nuova ImmutableMatrixclasse astratta che potrebbe avere ImmutableArrayBackedMatrixcome sottotipi anche le classi non supportate sopra menzionate.

Si noti che tale refactoring non sarebbe impedito dal fatto che la lingua "consenta" ImmutableMatrixdi esaminare l'array di supporto per istanze diverse da this, a meno che la lingua non abbia sfruttato tale abilità e abbia effettivamente esaminato istanze esterne. L'effetto principale di avere un linguaggio limita tale utilizzo è che farà immediatamente scricchiolare il compilatore a qualsiasi tentativo di scrivere codice che non sarebbe suscettibile di tale refactoring.


2

Java non è strettamente un linguaggio orientato agli oggetti, ma un linguaggio basato sulla classe : la classe determina le operazioni e l'accesso al comportamento piuttosto che l'istanza.

Quindi non essere troppo sorpreso dal fatto che ti consente di fare cose che non sono strettamente orientate agli oggetti.

Poiché il metodo è nello stesso ambito di classe dell'istanza, ha pieno accesso ai membri privati. Regole simili regolano istanze di classi interne che accedono ai dati da istanze di classi esterne: un'istanza di una classe interna può accedere a membri privati ​​della classe esterna.

Questo è ereditato dal C ++, dove è utile per creare costruttori di copia e spostamento. È anche utile per confrontare o combinare due oggetti in cui il loro valore dipende da membri che non sono accessibili pubblicamente in modo efficiente (ad esempio, il getter per un array in Java dovrebbe copiare l'array in modo che il codice client non possa modificarlo, cambiando lo stato interno dell'oggetto, ma non è necessario copiare le matrici per confrontare l'uguaglianza degli oggetti)

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.