J'ai observé que les classes externes peuvent accéder aux variables d'instance privée des classes internes. Comment est-ce possible? Voici un exemple de code démontrant la même chose:
class ABC{
class XYZ{
private int x=10;
}
public static void main(String... args){
ABC.XYZ xx = new ABC().new XYZ();
System.out.println("Hello :: "+xx.x); ///Why is this allowed??
}
}
Pourquoi ce comportement est-il autorisé?
new ABC().new XYZ()
Réponses:
La classe interne est juste un moyen de séparer proprement certaines fonctionnalités qui appartiennent vraiment à la classe externe d'origine. Ils sont destinés à être utilisés lorsque vous avez 2 exigences:
Compte tenu de ces exigences, les classes internes ont un accès complet à leur classe externe. Puisqu'ils sont fondamentalement membres de la classe externe, il est logique qu'ils aient accès aux méthodes et attributs de la classe externe - y compris les privates.
la source
Si vous souhaitez masquer les membres privés de votre classe interne, vous pouvez définir une interface avec les membres publics et créer une classe interne anonyme qui implémente cette interface. Exemple ci-dessous:
class ABC{ private interface MyInterface{ void printInt(); } private static MyInterface mMember = new MyInterface(){ private int x=10; public void printInt(){ System.out.println(String.valueOf(x)); } }; public static void main(String... args){ System.out.println("Hello :: "+mMember.x); ///not allowed mMember.printInt(); // allowed } }
la source
x
c'est public ici, ce n'est pas autorisé commemMember.x
.La classe interne est (à des fins de contrôle d'accès) considérée comme faisant partie de la classe contenant. Cela signifie un accès complet à tous les privés.
La façon dont cela est implémenté utilise des méthodes synthétiques protégées par un package: la classe interne sera compilée dans une classe distincte dans le même package (ABC $ XYZ). La JVM ne prend pas en charge ce niveau d'isolation directement, de sorte qu'au niveau du bytecode ABC $ XYZ aura des méthodes protégées par package que la classe externe utilise pour accéder aux méthodes / champs privés.
la source
Une réponse correcte apparaît sur une autre question similaire à celle-ci: Pourquoi le membre privé d'une classe imbriquée est-il accessible par les méthodes de la classe englobante?
Il dit qu'il existe une définition de la portée privée sur JLS - Détermination de l'accessibilité :
la source
Un cas d'utilisation important à mon humble avis pour les classes internes est le modèle d'usine. La classe englobante peut préparer une instance de la classe interne sans restrictions d'accès et transmettre l'instance au monde extérieur, où l'accès privé sera respecté.
Contrairement à abyx, déclarer la classe static ne modifie pas les restrictions d'accès à la classe englobante, comme indiqué ci-dessous. Les restrictions d'accès entre les classes statiques de la même classe englobante fonctionnent également. J'ai été surpris ...
class MyPrivates { static class Inner1 { private int test1 = 2; } static class Inner2 { private int test2 = new Inner1().test1; } public static void main(String[] args) { System.out.println("Inner : "+new Inner2().test2); } }
la source
Thilo a ajouté une bonne réponse à votre première question "Comment est-ce possible?". Je souhaite développer un peu la deuxième question posée: pourquoi ce comportement est-il autorisé?
Pour commencer, soyons parfaitement clairs sur le fait que ce comportement n'est pas limité aux classes internes, qui par définition sont des types imbriqués non statiques. Ce comportement est autorisé pour tous les types imbriqués, y compris les énumérations imbriquées et les interfaces qui doivent être statiques et ne peuvent pas avoir d'instance englobante. Fondamentalement, le modèle est une simplification jusqu'à la déclaration suivante: le code imbriqué a un accès complet au code englobant - et vice versa.
Alors, pourquoi alors? Je pense qu'un exemple illustre mieux ce point.
Pensez à votre corps et à votre cerveau. Si vous injectez de l'héroïne dans votre bras, votre cerveau devient haut. Si la région de l'amygdale de votre cerveau voit ce qu'il croit être une menace pour votre sécurité personnelle, disons une guêpe par exemple, il fera tourner votre corps dans l'autre sens et courra vers les collines sans que vous «y pensiez» deux fois.
Ainsi, le cerveau est une partie intrinsèque du corps - et curieusement, l'inverse aussi. L'utilisation du contrôle d'accès entre ces entités étroitement liées renonce à leur revendication de relation. Si vous avez besoin d'un contrôle d'accès, vous devez séparer davantage les classes en unités vraiment distinctes. Jusque-là, ils sont la même unité. Un exemple de conduite pour d'autres études serait d'examiner comment un Java
Iterator
est généralement implémenté.L'accès illimité du code englobant au code imbriqué rend, pour la plupart, plutôt inutile d'ajouter des modificateurs d'accès aux champs et aux méthodes d'un type imbriqué. Cela ajoute de l'encombrement et pourrait donner un faux sentiment de sécurité aux nouveaux arrivants du langage de programmation Java.
la source
Les restrictions d'accès sont effectuées par classe. Il n'existe aucun moyen pour une méthode déclarée dans une classe de ne pas pouvoir accéder à tous les membres de l'instance / de la classe. Cela va de soi que les classes internes ont également un accès sans entrave aux membres de la classe externe, et que la classe externe a un accès sans entrave aux membres de la classe interne.
En plaçant une classe dans une autre classe, vous la rendez étroitement liée à l'implémentation, et tout ce qui fait partie de l'implémentation doit avoir accès aux autres parties.
la source
La logique derrière les classes internes est que si vous créez une classe interne dans une classe externe, c'est parce qu'elles auront besoin de partager quelques choses, et il est donc logique qu'elles puissent avoir plus de flexibilité que les classes «régulières».
Si, dans votre cas, cela n'a aucun sens pour les classes d'être capables de voir le fonctionnement interne de l'autre - ce qui signifie essentiellement que la classe interne aurait simplement pu être transformée en classe régulière, vous pouvez déclarer la classe interne comme
static class XYZ
. L'utilisationstatic
signifiera qu'ils ne partageront pas l'état (et, par exemplenew ABC().new XYZ()
, ne fonctionnera pas, et vous devrez l'utilisernew ABC.XYZ()
.Mais, si c'est le cas, vous devriez vous demander si cela
XYZ
devrait vraiment être une classe interne et que peut-être qu'elle mérite la sienne fichier. Parfois, il est judicieux de créer une classe interne statique (par exemple, si vous avez besoin d'une petite classe qui implémente une interface que votre classe externe utilise, et cela ne sera utile nulle part ailleurs). Mais à peu près la moitié du temps il aurait dû devenir une classe extérieure.la source
La classe interne est considérée comme un attribut de la classe externe. Par conséquent, peu importe que la variable d'instance de la classe interne soit privée ou non, la classe externe peut y accéder sans aucun problème, tout comme accéder à ses autres attributs privés (variables).
class Outer{ private int a; class Inner{ private int b=0; } void outMethod(){ a = new Inner().b; } }
la source
Parce que votre
main()
méthode est dans laABC
classe, qui peut accéder à sa propre classe interne.la source
ABC
classe peuvent accéder aux classes imbriquées dans laABC
classe, mais pourquoi ils peuvent accéder aux membres privés des classes imbriquées dans laABC
classe en Java.