Pourquoi les classes Java externes peuvent-elles accéder aux membres privés de la classe interne?

J’ai observé que les classes externes peuvent accéder aux variables d’instance privées 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(Ssortingng... args){ ABC.XYZ xx = new ABC().new XYZ(); System.out.println("Hello :: "+xx.x); ///Why is this allowed?? } } 

Pourquoi ce comportement est-il autorisé?

    La classe interne est juste un moyen de séparer proprement certaines fonctionnalités appartenant réellement à la classe externe d’origine. Ils sont destinés à être utilisés lorsque vous avez 2 exigences:

    1. Certaines fonctionnalités de votre classe externe seraient plus claires si elles étaient implémentées dans une classe distincte.
    2. Même si elle est dans une classe distincte, la fonctionnalité est étroitement liée au fonctionnement de la classe externe.

    Compte tenu de ces exigences, les classes internes ont un access complet à leur classe externe. Comme ils sont fondamentalement membres de la classe externe, il est logique qu’ils aient access aux méthodes et aux atsortingbuts de la classe externe, y compris les classes privées.

    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(Ssortingng.valueOf(x)); } }; public static void main(Ssortingng... args){ System.out.println("Hello :: "+mMember.x); ///not allowed mMember.printInt(); // allowed } } 

    La classe interne est (aux fins du contrôle d’access) considérée comme faisant partie de la classe contenant. Cela signifie un access complet à tous les privés.

    La manière dont cela est mis en œuvre 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 machine virtuelle Java ne prend pas directement en charge ce niveau d’isolement, de sorte qu’au niveau du code octet, ABC $ XYZ aura des méthodes protégées par le package que la classe externe utilisera pour accéder aux méthodes / champs privés.

    Une réponse correcte apparaît sur une autre question similaire à celle-ci: Pourquoi le membre privé d’une classe nestede peut-il être accédé par les méthodes de la classe englobante?

    Il dit qu’il y a une définition de la scope privée sur JLS – Détermination de l’accessibilité :

    Sinon, si le membre ou le constructeur est déclaré privé, alors l’access est autorisé si et seulement si cela se produit dans le corps de la classe de niveau supérieur (§6.6) qui contient la déclaration du membre ou du constructeur.

    Un cas d’utilisation IMHO important pour les classes internes est le motif d’usine. La classe englobante peut préparer une instance de la classe interne sans ressortingctions d’access et transmettre l’instance au monde extérieur, où l’access privé sera respecté.

    En contradiction avec la déclaration de la classe statique, abyx ne modifie pas les ressortingctions d’access à la classe englobante, comme indiqué ci-dessous. Les ressortingctions d’access 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(Ssortingng[] args) { System.out.println("Inner : "+new Inner2().test2); } } 

    Les ressortingctions d’access sont effectuées par classe. Il n’y a aucun moyen pour une méthode déclarée dans une classe de ne pas pouvoir accéder à tous les membres d’instance / classe. Cela signifie que les classes internes ont également un access illimité aux membres de la classe externe et que la classe externe a un access illimité 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 access aux autres parties.

    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 “normales”.

    Si, dans votre cas, il n’est pas logique que les classes puissent voir le fonctionnement interne de l’autre – ce qui signifie essentiellement que la classe interne pourrait simplement être une classe régulière, vous pouvez déclarer la classe interne comme static class XYZ . Utiliser static signifiera qu’ils ne partageront pas d’état (et, par exemple, new ABC().new XYZ() ne fonctionnera pas, et vous devrez utiliser new ABC.XYZ() .
    Mais si tel est le cas, vous devriez vous demander si XYZ devrait vraiment être une classe interne et que cela mérite peut-être son propre 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 utilisée par votre classe externe, et qui ne sera pas utile ailleurs). Mais à peu près la moitié du temps, il aurait fallu en faire une classe externe.

    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 est non seulement autorisé pour les classes internes qui, par définition, sont des types nesteds non statiques. Ce comportement est autorisé pour tous les types nesteds, y compris les énumérations et interfaces nestedes, qui doivent être statiques et ne peuvent pas comporter d’instance englobante. Fondamentalement, le modèle est une simplification jusqu’à la déclaration suivante: le code nested a un access complet au code englobant – et vice versa.

    Alors, pourquoi alors? Je pense qu’un exemple illustre mieux le point.

    Pensez à votre corps et à votre cerveau. Si vous injectez de l’héroïne dans votre arm, votre cerveau devient haut. Si la région amygdale de votre cerveau voit ce qu’il croit être une menace pour votre sécurité personnelle, par exemple une guêpe, il fera tourner votre corps et courra vers les collines sans que vous ne le pensiez deux fois.

    Ainsi, le cerveau est une partie insortingnsèque du corps – et étrangement, l’inverse aussi. L’utilisation du contrôle d’access entre ces entités étroitement liées renonce à leur revendication de relation. Si vous avez besoin d’un contrôle d’access, vous devez séparer davantage les classes en unités vraiment distinctes. Jusque-là, ils sont la même unité. Un exemple à suivre pour des études ultérieures consisterait à examiner comment un Java Iterator est généralement implémenté.

    L’access illimité du code au code nested rend la plupart du temps inutile pour append des modificateurs d’access aux champs et aux méthodes d’un type nested. Cela ajoute du désordre et pourrait créer un faux sentiment de sécurité pour les nouveaux utilisateurs du langage de programmation Java.

    La classe interne est considérée comme un atsortingbut de la classe externe. Par conséquent, quelle que soit la variable d’instance de classe Inner, qu’elle soit privée ou non, la classe Outer peut accéder sans problème, tout comme l’access à ses autres atsortingbuts privés (variables).

     class Outer{ private int a; class Inner{ private int b=0; } void outMethod(){ a = new Inner().b; } } 

    Parce que votre méthode main() est dans la classe ABC , qui peut accéder à sa propre classe interne.