In der Java -Programmierung wird ein Mitglied mithilfe des privaten Schlüsselworts geändert. Nur die Klasse, in der sich dieses Mitglied befindet, und die Methode dieser Klasse kann verwendet werden, und andere Klassen können nicht auf dieses private Mitglied zugreifen.
Das obige beschreibt die Grundfunktionen des privaten Modifikators. Lassen Sie uns heute die Situation des privaten Funktionsfehlers untersuchen.
Java interne Klassen
In Java glaube ich, dass viele Menschen interne Klassen benutzt haben. Java ermöglicht es, eine andere Klasse in einer Klasse zu definieren. Die Klasse in der Klasse ist eine interne Klasse, die auch als verschachtelte Klasse bezeichnet wird. Eine einfache interne Klassenimplementierung kann wie folgt sein
Klasse OuterClass {Klasse Innerclass {}}Das heutige Problem hängt mit Java -internen Klassen zusammen und beinhaltet nur einige interne Klassenkenntnisse in Bezug auf die Forschung dieses Artikels. Wir werden die folgenden Artikel zu Java -internen Klassen einführen.
Das erste Mal, dass es fehlschlug?
Ein Szenario, das wir häufig in der Programmierung verwenden, besteht darin, auf private Mitgliedsvariablen oder Methoden externer Klassen in einer internen Klasse zuzugreifen, was in Ordnung ist. Wie im folgenden Code implementiert.
public class OUTERCLASS {private string langer = "en"; private Stringregion = "US"; öffentliche Klasse Innerclass {public void printouterClassPrivateFields () {String fields = "Sprache =" + Sprache + "; Region =" + Region; System.out.println (Felder); }} public static void main (String [] args) {äußere klasse äußere = new outerClass (); OuterClass.InnerClass inner = äußere.new InnerClass (); Inner.printouterClassprivateFields (); }}Warum ist das? Ist nicht von der vom Mitglied beschriebenen Klasse ein privatem modifiziertes Mitglied zugänglich? Ist privat wirklich ungültig?
Der Compiler spielt herum?
Wir verwenden den Befehl javap, um die generierten zwei Klassendateien anzuzeigen
Dekompilierungsergebnisse der äußeren Klasse
15:30 $ javap -c outerClasscompiled aus "äußereklasse.java" öffentliche Klasse OuterClass erweitert Java.lang.Object {public oterclass (); Code: 0: ALOAD_0 1: Invokespecial #11; // Methode Java/Lang/Objekt. "<Init>" :() v 4: ALOAD_0 5: LDC #13; // String En 7: Putfield #15; // Feldsprache: Ljava/Lang/String; 10: ALOAD_0 11: LDC #17; // String US 13: Putfield #19; // Feldregion: Ljava/Lang/String; 16: returnPublic static void main (Java.lang.String []); Code: 0: Neu #1; // Klasse OuterClass 3: DUP 4: Invokespecial #27; // Methode "<Init>" :() v 7: store_1 8: neu #28; // Klasse OuterClass $ InnerClass 11: DUP 12: ALOAD_1 13: DUP 14: InvokeVirtual #30; // Methode Java/Lang/Object.getClass :() Ljava/Lang/Klasse; 17: Pop 18: Invokespecial #34; // Methode OuterClass $ InnerClass. "<In>" :( LouterClass;) v 21: store_2 22: ALOAD_2 23: InvokeVirtual #37; // Methode OuterClass $ InnerClass.printouterClassprivateFields :() V 26: returnstatic Java.lang.String Access $ 0 (äußere klasse); Code: 0: ALOAD_0 1: Getfield #15; // Feldsprache: Ljava/Lang/String; 4: Areturnstatic Java.lang.String Access $ 1 (äußere Klasse); Code: 0: ALOAD_0 1: Getfield #19; // Feldregion: Ljava/Lang/String; 4: Areturn}Huh? Nein, wir definieren diese beiden Methoden nicht in der Außenklasse
statischer Java.lang.String Access $ 0 (äußere Klasse); Code: 0: ALOAD_0 1: Getfield #15; // Feldsprache: Ljava/Lang/String; 4: Areturnstatic Java.lang.String Access $ 1 (äußere Klasse); Code: 0: ALOAD_0 1: Getfield #19; // Feldregion: Ljava/Lang/String; 4: Areturn}
Nach den angegebenen Kommentaren zu urteilen, gibt der Zugriff $ 0 das Sprachattribut der äußeren Klasse zurück. Zugriff $ 1 gibt das Region -Attribut der äußeren Klasse zurück. Und beide Methoden akzeptieren eine Instanz von äußerer Klassen als Parameter. Warum werden diese beiden Methoden erzeugt und wie sind ihre Funktionen? Schauen wir uns die Dekompilierungsergebnisse der internen Klasse an.
Dekompilierungsergebnis von äußere Klassen $ Innerclass
15:37 $ javap -c outerClass/$ InnerClasscompiled von "OuterClass.java" Public Class OuterClass $ Innerclass erweitert Java.lang.object (endgültige äußere Klasse Diese $ 0; öffentliche äußere Klasse $ Innerklasse (OUTERCLASS); Code: 0: ALOAD_0 1: ALOAD_1 2: Putfield #10; // Feld Diese $ 0: LouterClass; 5: ALOAD_0 6: Invokespecial #12; // Methode Java/Lang/Objekt. "<Init>" :() v 9: returnpublic void printouterClassprivateFields (); Code: 0: neu #20; // Klasse Java/Lang/StringBuilder 3: DUP 4: LDC #22; // String Language = 6: Invokespecial #24; // Methode Java/Lang/StringBuilder. "<In init>" :( Ljava/Lang/String;) V 9: ALOAD_0 10: GetField #10; // Feld Diese $ 0: LouterClass; 13: invokestatic #27; // method outclass.access $ 0: (louterClass;) ljava/lang/string; 16: InvokeVirtual #33; // Methode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/Lang/StringBuilder; 19: LDC #37; // String; Region = 21: InvokeVirtual #33; // Methode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/Lang/StringBuilder; 24: ALOAD_0 25: Getfield #10; // Feld Diese $ 0: LouterClass; 28: invokestatic #39; // Methode äußereClass.Access $ 1: (louterClass;) ljava/lang/String; 31: InvokeVirtual #33; // Methode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/Lang/StringBuilder; 34: InvokeVirtual #42; // Methode Java/Lang/StringBuilder.toString :() Ljava/Lang/String; 37: Store_1 38: Getstatic #46; // Feld Java/Lang/System.out: ljava/io/printstream; 41: ALOAD_1 42: InvokeVirtual #52; // Methode java/io/printstream.println: (ljava/lang/string;) v 45: return}
Der folgende Code ruft den Zugriff auf $ 0 -Code auf, um die Sprach private Eigenschaft von äußererklasse zu erhalten.
13: invokestatic #27; // method outclass.access $ 0: (louterClass;) ljava/lang/string;
Der folgende Code ruft den Zugriff auf 1 $ 1 auf, um die Region Private -Eigenschaft von äußere Klassen zu erhalten.
28: invokestatic #39; // Methode äußereClass.Access $ 1: (louterClass;) ljava/lang/String;
Hinweis: Beim Bau einer inneren Klasse wird der Verweis auf die äußere Klasse übergeben und als Eigenschaft der inneren Klasse verwendet, sodass die innere Klasse einen Verweis auf ihre äußere Klasse hat.
Diese $ 0 ist die externe Klassenreferenz, die von der inneren Klasse gehalten wird und die Referenz übergibt und den Wert über den Konstruktor zuweist.
endgültige äußere Klasse Diese $ 0; öffentliche äußere Klasse $ Innerclass (äußere Klasse); Code: 0: ALOAD_0 1: ALOAD_1 2: Putfield #10; // Feld Diese $ 0: LouterClass; 5: ALOAD_0 6: Invokespecial #12; // Methode Java/Lang/Objekt. "<Init>" :() v 9: Rückgabe
Zusammenfassung
Dieser Teil von privat scheint ungültig zu sein, ist jedoch nicht ungültig, denn wenn die innere Klasse die privaten Eigenschaften der äußeren Klasse aufruft, besteht die reale Ausführung darin, die statischen Methoden der vom Compiler generierten Attribute (d. H. ACESS $ 0, Zugriff $ 1 usw.) aufzurufen, um diese Attributwerte zu erhalten. All dies ist ein besonderer Umgang mit dem Compiler.
Diesmal ist es ungültig?
Wenn die obige Schreibmethode sehr häufig verwendet wird, wird diese Schreibmethode selten freigelegt, kann aber ausgeführt werden.
public class AnotherouterClass {public static void main (String [] args) {Innerclass inner = new AnotherouterClass (). New InnerClass (); System.out.println ("Innerclass fehlgeschlagen =" + inner.x); } Klasse Innerclass {private int x = 10; }}Verwenden Sie wie oben Javap, um zu dekompilieren und einen Blick darauf zu werfen. Aber diesmal sehen wir uns zuerst die Ergebnisse der Innenklasse an
16:03 $ javap -c eine andere untergebe/$ InnerClasscompiled aus "AnotherouterClass.java" -Klasse eine andere untergebrachte Klasse $ Innerclass erweitert java.lang.object {endgültig eine andere Einführung von 0 $ 0; ein weiterer Mouterclass $ Innerclass (ein weiterer Outerclasse); Code: 0: ALOAD_0 1: ALOAD_1 2: PUTFIELD #12; // Feld Diese $ 0: LanotherouterClass; 5: ALOAD_0 6: Invokespecial #14; // Methode Java/Lang/Objekt. "<Init>" :() v 9: aload_0 10: bipush 10 12: putfield #17; // Feld X: I 15: returnstatic int Access $ 0 (eine andere Untersuchung $ Innerclass); Code: 0: ALOAD_0 1: Getfield #17; // Feld X: I 4: Ireturn}Es wird erneut angezeigt, und der Compiler generiert automatisch eine Backdoor -Methode, um private Attribute zugreifen zu können, um den Wert von x zu erhalten.
Eine weitere Dekompilierung der UnterouterClass.Class zu Ergebnissen
16:08 $ javap -c Eine andere outerClasscompiled aus "AnotherouterClass.java" öffentliche Klasse Eine andereOuterClass erweitert Java.lang.Object {public AnotherouterClass (); Code: 0: ALOAD_0 1: Invokespecial #8; // Methode Java/Lang/Objekt. "<Init>" :() v 4: returnPublic static void main (Java.lang.String []); Code: 0: Neu #16; // Klasse eine andere Verzeichnis $ InnerClass 3: DUP 4: Neu #1; // Klasse eine andere Taste 7: DUP 8: Invokespecial #18; // Methode "<Init>" :() V 11: DUP 12: InvokeVirtual #19; // Methode Java/Lang/Object.getClass :() Ljava/Lang/Klasse; 15: Pop 16: Invokespecial #23; // Methode eine andere Verzeichnis $ InnerClass. // Feld Java/Lang/System.out: ljava/io/printstream; 23: Neu #32; // Klasse Java/Lang/StringBuilder 26: DUP 27: LDC #34; // String Innerclass Appleed = 29: Invokespecial #36; // Methode Java/Lang/StringBuilder. "<In init>" :( Ljava/Lang/String;) V 32: ALOAD_1 33: invokestatic #39; // Methode eine andere Taste $ Innerclass.access $ 0: (LanotherouterClass $ Innerclass;) I 36: InvokeVirtual #43; // Methode Java/Lang/StringBuilder.Append: (i) ljava/lang/StringBuilder; 39: InvokeVirtual #47; // Methode Java/Lang/StringBuilder.toString :() Ljava/Lang/String; 42: InvokeVirtual #51; // Methode java/io/printstream.println: (ljava/lang/string;) v 45: return}Dieser Anruf ist der Betrieb der externen Klasse, um private Attribut X über eine Instanz der internen Klasse zu erhalten.
33: invokestatic #39; // Methode eine andere Verzeichnis $ InnerClass.access $ 0: (LanotherouterClass $ Innerclass;) i
Lassen Sie uns eine weitere Zusammenfassung haben
Das offizielle Java -Dokument gibt einen Satz
Wenn das Mitglied oder der Konstruktor privat erklärt wird, ist der Zugang nur dann zulässig, wenn er im Körper der obersten Klasse (§ 7.6) auftritt, die die Erklärung des Mitglieds oder des Konstruktors einschließt.
Bedeutet, wenn (Mitglieder der inneren Klasse) und Konstruktoren als private Modifikatoren festgelegt sind, die nur dann zulässig sind, wenn ihre externe Klasse zugreift.
Wie man verhindern, dass private Mitglieder interner Klassen von extern zugänglich sind
Ich glaube, dass Sie nach dem Lesen der oben genannten zwei Teile für private Mitglieder interner Klassen schwierig sind, nicht von externen Klassen zugegriffen zu werden. Wer kann den Compiler "neugierig" machen? Es kann tatsächlich getan werden. Das heißt, anonyme innere Klassen zu verwenden.
Da die Art des mrunnablen Objekts ausgelastet ist, nicht die Art der anonymen inneren Klasse (wir können es normal nicht bekommen), und es gibt keine X -Eigenschaft in Runanble, Mrunnable.x ist nicht zulässig.
public class privatetouter {runnable mrunnable = new Runnable () {private int x = 10; @Override public void run () {System.out.println (x); }}; public static void main (String [] args) {privatetouter p = neuer privatetouter (); //System.out.println("anonymous class private arred = "+ p.mrunnable.x); // nicht erlaubt p.mrunnable.run (); // erlaubt }}Abschlusszusammenfassung
In diesem Artikel scheint privat auf der Oberfläche ungültig zu sein, aber tatsächlich nicht. Stattdessen werden private Eigenschaften durch indirekte Methoden erhalten, wenn sie aufgerufen werden.
Die interne Klassenkonstruktion von Java hält Anwendungen für externe Klassen, aber C ++, was sich nicht von C ++ unterscheidet.
Bücher, die tief in Java -Details eingehen
Java -Programmierideen
Die Kerntechnologieserie von Sun Company: Effektive Java Chinesische Version Verständnis Java Virtual Machine: Erweiterte Funktionen und Best Practices von JVM
Das obige ist eine Zusammenstellung der Informationen zu Java -privaten Modifikatoren. Wir werden in Zukunft weiterhin relevante Informationen hinzufügen. Vielen Dank für Ihre Unterstützung für diese Seite!