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.
Warum denkst du, dass Aussage 1 ungültig ist? –
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
[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)) –