it-swarm.com.de

Warum ist ein privates Mitglied in einer statischen Methode zugänglich?

Das Folgende ist Pseudocode, ich habe es in Java und PHP und beide haben funktioniert) versucht:

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();

Warum können Sie dies in OOP Paradigma und was ist der Nutzen davon?

25
Ben

In Java sind private Variablen für die gesamte Klasse sichtbar. Auf sie kann über statische Methoden und über andere Instanzen derselben Klasse zugegriffen werden.

Dies ist beispielsweise in Factory-Methoden nützlich. Eine Factory-Methode führt normalerweise Initialisierungen für ein Objekt durch, die so komplex sind, dass Sie sie nicht dem Anwendungscode überlassen möchten. Für die Initialisierung benötigt die Factory-Methode häufig Zugriff auf die Klasseneinbauten, die Sie nicht verfügbar machen möchten. Der direkte Zugriff auf die privaten Variablen erleichtert Ihnen das Leben erheblich.

Wenn Sie jedoch die Implementierungsdetails einer Klasse auch vor statischen Methoden oder vor anderen Instanzen dieser Klasse verbergen möchten, können Sie dem privates Klassendatenmuster folgen. Fügen Sie alle privaten Variablen einer Klasse in eine private innere Klasse ein und delegieren Sie alle Getter oder Setter an Getter und Setter dieser inneren Klasse.

Eine andere Möglichkeit besteht darin, eine Schnittstelle für die Klasse zu definieren, die alle öffentlichen Methoden der Klasse deklariert, und dann, wo immer möglich, nur auf die Klasse unter dieser Schnittstelle zu verweisen. Ein Verweis auf den Schnittstellentyp kann nicht verwendet werden, um direkt auf etwas zuzugreifen, das nicht in der Schnittstelle deklariert ist, egal wo (außer natürlich mit Reflexion). Wenn Sie eine objektorientierte Programmiersprache verwenden, die keine Schnittstellen hat (wie z. B. C++), können diese mit einer abstrakten Basisklasse simuliert werden, die von der tatsächlichen Klasse geerbt wird.

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
    }

}
17
Philipp

Einige Sprachen und Laufzeit-Frameworks (z. B. Java, .NET) gehen davon aus, dass jedem, der den Code für eine bestimmte Klasse kompiliert, vertraut werden kann, dass er keine privaten Mitglieder einer Instanz dieser Klasse auf eine Weise verwendet, die sich nachteilig auf deren Richtigkeit auswirkt Betrieb. Andere Sprachen und Frameworks sind in dieser Hinsicht restriktiver und erlauben keinen Zugriff auf private Mitglieder einer Instanz, außer durch Code, der auf dieser Instanz ausführt. Beide Designs haben Vor- und Nachteile.

Der größte Vorteil, wenn Code innerhalb einer Klasse auf private Mitglieder einer Instanz zugreifen kann, besteht darin, dass es Fälle gibt, in denen diese Zugriffsebene angemessen ist. Wenn private auf diese Weise funktioniert, muss kein anderer Zugriff erforderlich sein Qualifizierer, die für diesen Zweck verfügbar sind, oder Code erzwingen, um Mitglieder breiter darzustellen, als dies sonst ideal wäre.

Ein Vorteil des Nichtzulassens eines solchen Zugriffs (wie dies im Microsoft Common Object Model (COM) der Fall war) besteht darin, dass externer Code Klassen als Schnittstellen behandeln kann. Wenn eine Klasse ImmutableMatrix ein privates oder geschütztes double[][] - Sicherungsfeld enthält und der Code in der Klasse das Sicherungsarray anderer Instanzen untersucht, kann kein Nicht-Array definiert werden. unterstützte Klasse (z. B. ZeroMatrix, IdentityMatrix), die von externem Code als Immutable2dMatrix verwendet werden kann, ohne dass diese Klasse das Hintergrundfeld einschließen muss. Wenn nichts in Immutable2dMatrix Private Mitglieder einer anderen Instanz als this verwendet, kann die Klasse in ImmutableArrayBackedMatrix umbenannt und eine neue Zusammenfassung ImmutableMatrix Klasse, die ImmutableArrayBackedMatrix sowie die oben genannten nicht Array-gestützten Klassen als Untertypen haben könnte.

Beachten Sie, dass ein solches Refactoring nicht verhindert werden würde, wenn die Sprache "$" ImmutableMatrix das Backing-Array auf andere Instanzen als this untersuchen lässt, es sei denn, die Sprache hat diese Fähigkeit ausgenutzt und tatsächlich außerhalb untersucht Instanzen. Der primäre Effekt einer Sprache, die eine solche Verwendung einschränkt, besteht darin, dass der Compiler bei jedem Versuch, Code zu schreiben, der für ein solches Refactoring nicht geeignet wäre, sofort kreischt.

3
supercat

Java ist keine streng objektorientierte Sprache, sondern eine klassenbasierte Sprache - die Klasse bestimmt die Operationen und den Verhaltenszugriff und nicht die Instanz.

Seien Sie also nicht übermäßig überrascht, dass Sie damit Dinge tun können, die nicht streng objektorientiert sind.

Da sich die Methode im selben Klassenbereich wie die Instanz befindet, hat sie vollen Zugriff auf private Mitglieder. Ähnliche Regeln gelten für Instanzen innerer Klassen, die auf Daten von Instanzen äußerer Klassen zugreifen. Eine Instanz einer inneren Klasse kann auf private Mitglieder der äußeren Klasse zugreifen.

Dies wird von C++ geerbt, wo es zum Erstellen von Kopier- und Verschiebungskonstruktoren nützlich ist. Es ist auch nützlich, um zwei Objekte zu vergleichen oder zu kombinieren, deren Wert von Mitgliedern abhängt, auf die auf effiziente Weise nicht öffentlich zugegriffen werden kann (z. B. sollte der Getter für ein Array in Java sollte das Array so kopieren) dass der Client-Code ihn nicht ändern kann, den internen Status des Objekts ändert, aber Arrays kopieren müssen, um die Objektgleichheit zu vergleichen, ist nicht effizient)

2
Pete Kirkham