2016-04-27 4 views
1
class TestMemberOuter1{ 
private int data=30; 
class Inner{ 
    void msg(){System.out.println("data is "+data);} 
} 

void display(){ 
    Inner in=new Inner(); 
    in.msg(); 
} 
public static void main(String args[]){ 
    TestMemberOuter1 obj=new TestMemberOuter1(); 
    obj.display(); 
} 
} 

Warum innere Klasse auf private Mitglieder der Oberklasse zugreifen kann?Wie werden private Member einer Klasse über Member-Funktionen der Klasse auf Speicherebene aufgerufen?

Ich möchte wissen, welche Implementierung [auf der unteren Ebene (vielleicht auf Speicherebene oder Java-Implementierung spezifische oder andere nicht sicher)] ermöglicht, diese Art von Verhalten in Java zu erreichen.

+2

Warum denkst du, dass Aussage 1 ungültig ist? –

+1

Das erste Statement ist nicht ungültig, da das main in derselben Klasse wie das private Member 'data' liegt, so dass Sie auf private Mitglieder der Klasse zugreifen können. – SomeJavaGuy

+0

[Warum sind private Felder für den Typ privat, nicht die Instanz?] (Http://stackoverflow.com/questions/6983553/why-are-private-fields-private-to-the-type-not-the-instance)) –

Antwort

3

Ich denke nicht, dass Sie weder eine Speicher-Level-Modifizierung oder Logik-Implementierung, um dies zu erreichen, noch ich denke, Java wird jede riesige Code-Logik auf der Speicherebene haben, um das gleiche zu implementieren.

Speicher hat nichts damit zu tun. Privat, öffentlich und geschützt sind nur ein Zugriffsfilter. Egal ob privat, öffentlich oder geschützt, alle diese Variablen befinden sich in einem Speicher, der für ein Objekt reserviert ist.

Es gibt keine unterschiedliche Speicherzuweisung für private, öffentliche oder geschützte Variablen. Sie sind letztlich alle die Eigenschaften desselben Objekts.

Dann, wie kommt Compiler behandelt dies ???

Sein bisschen einfacher als das.

Diese Zugriffsfilter geben eindeutig an, in welchen Kontext sie zugreifen dürfen.

Private: Nur in der Klasse :) Immer wenn der Compiler die Variable sieht, auf die zugegriffen wird, wird die Fehlerursache angezeigt.

Geschützt: Alle Klassen innerhalb des gleichen Pakets :) Immer wenn der Compiler die Variable sieht, auf die geschützt wird, wird auf ein beliebiges, ausstehendes Paket zugegriffen, das den Fehler Thats all anzeigt.

Öffentlich: Zugriff auf alle :) Keine Flags.

Remember Zugriff auf Variablen außerhalb Kontext führt zu Compiler-Fehler nicht Laufzeitfehler ?? Aus dem gleichen Grunde.

Sie brauchen nicht eine riesige Logik dahinter, einfach die Liste der privaten, geschützten und öffentlichen Variablen zu halten und überprüfen Sie ihre Verwendung ist angemessen oder nicht das ist alles.

EDIT Wie pro Ihre aktualisierte Frage „Warum Innerclass private Mitglieder des outerclass zugreifen kann?“

Die Schlussfolgerung aus der gleichen Analogie, die ich oben erläutert habe, erlaubt den Zugriff auf private Variablen innerhalb der Klasse.

Jetzt wo wird deine innere Klasse erklärt? Als Teil deiner äußeren Klasse ist es das nicht. Wenn Sie also auf die private Variable der äußeren Klasse innerhalb des inneren Klassencompilers zugreifen, hat das kein Problem damit, weil Ihre innere Klasse selbst innerhalb der äußeren Klasse liegt.

Ich hoffe, dass ich mit meiner Antwort ein wenig Sinn gemacht :) Happy Coding.

+3

Sieht aus wie Sie Ihren Zeitraum Schlüssel mit Ihrem Smiley-Schlüssel verwirrt. – shmosel

+0

@shmosel: hehehehehehe Entschuldigung, schlechte wabbit von mir Lemme aktualisieren Sie die Antwort, indem Sie sie entfernen. –

0

Gegenwärtig werden innere Klassen in verschiedene Klassendateien kompiliert, aber der Compiler fügt synthetische Hilfsmethoden ein, wenn ein Zugriff auf ein private Member über verschachtelte Klassen besteht. Die synthetische Methode selbst wird einen paketprivaten Zugriff haben und den Zugriff auf das Mitglied private innerhalb seiner eigenen Klasse ausführen.

Dies kann mit private Methoden nachgewiesen werden, wie deren Ausführung zurückverfolgt werden können und die Ausführung dieser Hilfsmethoden zeigen:

public class OuterClass { 
    static class InnerClass { 
     private static void test() { 
      OuterClass.privateMethod(); 
     } 
    } 
    private static void privateMethod() { 
     Thread.dumpStack(); 
    } 
    public static void main(String[] args) { 
     InnerClass.test(); 
    } 
} 

Das Ausführen dieses Programms gedruckt wird:

java.lang.Exception: Stack trace 
    at java.lang.Thread.dumpStack(Thread.java:1329) 
    at OuterClass.privateMethod(OuterClass.java:9) 
    at OuterClass.access$000(OuterClass.java:2) 
    at OuterClass$InnerClass.test(OuterClass.java:5) 
    at OuterClass$InnerClass.access$100(OuterClass.java:3) 
    at OuterClass.main(OuterClass.java:12) 

Diese verschachtelten Klassen werden in zwei verschiedene Klassendateien OuterClass.class und OuterClass$InnerClass.class kompiliert. Sie können sehen, dass der Compiler die synthetische Methode access$100 in OuterClass$InnerClass eingefügt hat, die es der main Methode von OuterClass ermöglicht, die private Methode test der inneren Klasse aufzurufen. Diese innere Klassenmethode hat wiederum eine synthetische Methode access$000 in der äußeren Klasse aufgerufen, die den Aufruf von privateMethod() in OuterClass ermöglicht.


Beachten Sie, dass diese Art von Zugriff auf den Zugang zu private Mitglieder mit Java 8 des Lambda-Ausdrücke und Verfahren Referenzen durchgeführt unterscheidet. Für den Memberzugriff, der in diesem Kontext ausgeführt wird, werden vom Compiler keine Hilfsmethoden generiert und die Art und Weise, in der die JVM den Zugriff ermöglicht, ist absichtlich nicht spezifiziert. Wir können jedoch sagen, dass für die aktuelle JRE-Implementierung von Oracle eine Laufzeitklasse generiert wird ist in der Tat in der Lage umgehen die Zugriffsbeschränkung von private Mitglieder, z

import java.util.function.Consumer; 

public class OuterClass { 
    static class InnerClass { 
     static final Consumer<Runnable> TEST_METHOD=InnerClass::test; 
     private static void test(Runnable outerMethod) { 
      outerMethod.run(); 
     } 
    } 
    private static void privateMethod() { 
     Thread.dumpStack(); 
    } 
    public static void main(String[] args) { 
     System.out.println(System.getProperty("java.version")); 
     InnerClass.TEST_METHOD.accept(OuterClass::privateMethod); 
    } 
} 

Ab 1.8.0_65, druckt es:

java.lang.Exception: Stack trace 
    at java.lang.Thread.dumpStack(Thread.java:1329) 
    at OuterClass.privateMethod(OuterClass.java:12) 
    at OuterClass$InnerClass.test(OuterClass.java:8) 
    at OuterClass.main(OuterClass.java:16) 

Nicht solche Hilfsmethoden zeigen, sondern auch die Laufzeit generierte Klassen herausgefiltert werden. Ändern privateMethod() zu

private static void privateMethod() { 
    for(StackTraceElement e:Thread.getAllStackTraces().get(Thread.currentThread())) 
     System.out.println("\tat "+e); 
} 

zeigt

at java.lang.Thread.dumpThreads(Native Method) 
    at java.lang.Thread.getAllStackTraces(Thread.java:1603) 
    at OuterClass.privateMethod(OuterClass.java:12) 
    at OuterClass$$Lambda$2/135721597.run(Unknown Source) 
    at OuterClass$InnerClass.test(OuterClass.java:8) 
    at OuterClass$InnerClass$$Lambda$1/471910020.accept(Unknown Source) 
    at OuterClass.main(OuterClass.java:16) 

mit den generierten Klassen mit ausgefallenen Namen wie OuterClass$InnerClass$$Lambda$1/471910020 und OuterClass$$Lambda$2/135721597, die die private Mitglieder zugreifen. Beachten Sie, dass die Generierung dieser Klassen durch die Klassen ausgelöst wurde, die das Recht haben, auf diese private-Member zuzugreifen, die überprüft wurden, bevor die Erstellung solcher Funktionsobjekte zugelassen wird.

Verwandte Themen