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

25

Quello che segue è 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?

    
posta Ben 02.07.2014 - 12:01
fonte

3 risposte

17

In Java, le variabili private sono visibili all'intera classe. È possibile accedervi da metodi statici e da altre istanze della stessa classe.

Questo è, ad esempio, utile nei metodi di fabbrica . Un metodo factory solitamente esegue le inizializzazioni su un oggetto che sono così complesse da non volerle lasciare al codice dell'applicazione. Per eseguire l'inizializzazione, il metodo factory spesso ha bisogno di accedere agli interni della classe che non vuoi esporre. Essere in grado di accedere direttamente alle variabili private rende la vita molto più semplice.

Tuttavia, quando desideri nascondere i dettagli di implementazione di una classe anche da metodi statici o da altre istanze di quella classe, puoi seguire schema dati classe privata . Metti tutte le variabili private di una classe in una classe interna privata e delegate eventuali getter o setter a getter e setter di quella classe interna.

Un'altra opzione è quella di definire un'interfaccia per la classe che dichiara tutti i metodi pubblici della classe e quindi di fare riferimento alla classe sotto quell'interfaccia ogni volta che è 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 usi un linguaggio di programmazione orientato agli oggetti che non ha interfacce (come C ++, per esempio), possono essere simulati con una classe base astratta che è ereditata dalla classe reale.

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
    }

}
    
risposta data 02.07.2014 - 12:32
fonte
3

Alcuni linguaggi e framework runtime (ad es. Java, .NET) presumono che chiunque stia compilando il codice per una particolare classe possa essere considerato attendibile non utilizzare alcun membro privato di alcuna istanza di quella classe in modi che sarebbero dannosi al suo corretto funzionamento. Altri linguaggi e framework sono più restrittivi al riguardo e non consentono l'accesso ai membri privati di un'istanza tranne che per il codice che esegue su quell'istanza . Entrambi i design hanno 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 avendo private funziona in questo modo elimina la necessità di avere un accesso diverso qualificatore disponibile a tale scopo o codice di forza per esporre i membri in modo più ampio di quanto sarebbe altrimenti ideale.

Un vantaggio nel 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 ImmutableMatrix contiene un campo di backup double[][] 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 esempio ZeroMatrix , IdentityMatrix ) che il codice esterno potrebbe utilizzare come Immutable2dMatrix , senza che la classe debba includere il campo di supporto. Se nulla in Immutable2dMatrix utilizza membri privati di qualsiasi istanza diversa da this , allora sarebbe possibile rinominare la classe in ImmutableArrayBackedMatrix e definire una nuova classe astratta ImmutableMatrix che potrebbe avere ImmutableArrayBackedMatrix e le suddette classi non supportate da array come sottotipi.

Si noti che tale refactoring non sarebbe impedito dal fatto che il linguaggio "consente" ImmutableMatrix di esaminare l'array di supporto per istanze diverse da this , a meno che il linguaggio non si avvalesse di tale abilità e in realtà esaminasse le istanze esterne. L'effetto principale di avere un linguaggio che limita tale utilizzo è che farà immediatamente squilibrare il compilatore in ogni tentativo di scrivere codice che non sarebbe suscettibile di tale refactoring.

    
risposta data 02.07.2014 - 21:57
fonte
2

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

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

Poiché il metodo si trova nello stesso ambito di classe dell'istanza, ha accesso completo ai membri privati. Regole simili governano le istanze di classi interne che accedono ai dati da istanze di classi esterne: un'istanza di una classe interna può accedere ai membri privati della classe esterna.

Questo è ereditato da C ++, dove è utile per creare copia e spostare i costruttori. È anche utile per confrontare o combinare due oggetti in cui il loro valore dipende da membri che non sono pubblicamente accessibili 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 dover copiare gli array per confrontare l'uguaglianza degli oggetti non è efficiente)

    
risposta data 03.07.2014 - 01:04
fonte

Leggi altre domande sui tag