Pourquoi les classes Java externes peuvent-elles accéder aux membres privés de 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(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é?

Author: Paŭlo Ebermann, 2009-11-26

10 answers

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:

  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 c'est dans une classe distincte, la fonctionnalité est très étroitement liée à la façon dont la classe externe fonctionne.

Compte tenu de ces exigences, les classes internes ont accès complet à leur classe extérieure. Comme ils sont essentiellement membres de la classe externe, il est logique qu'ils aient accès aux méthodes et aux attributs de la classe externe-y compris les privés.

 78
Author: Kaleb Brasee, 2009-11-26 05:52:13

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
    }
}
 53
Author: Ich, 2018-08-22 21:09:58

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 particuliers.

La façon dont cela est implémenté utilise des méthodes synthétiques protégées par des paquets: La classe interne sera compilée dans une classe distincte dans le même paquet (ABC$XYZ). La JVM ne prend pas directement en charge ce niveau d'isolation, de sorte qu'au niveau du bytecode ABC ABC XYZ aura des méthodes protégées par les paquets que la classe externe utilise pour accéder au privé les méthodes et les champs.

 48
Author: Thilo, 2009-11-26 06:01:18

Il y a une réponse correcte apparaissant sur une autre question similaire à celle-ci: Pourquoi le membre privé d'une classe imbriquée être accessibles par les méthodes de la classe englobante?

Il dit qu'il y a une définition de la portée privée sur JLS-Déterminer l'accessibilité :

Sinon, si le membre ou le constructeur est déclaré privé, alors l'accès est autorisé si et seulement s'il se produit dans le corps de la classe de niveau supérieur (§7.6) qui entoure le déclaration du membre ou du constructeur.

 14
Author: Colin Su, 2017-05-23 12:26:36

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 honoré.

En contradiction avec abyx déclarer la classe statique ne modifie pas les restrictions d'accès à la classe englobante, comme indiqué ci-dessous. De plus, les restrictions d'accès entre les classes statiques de la même classe englobante fonctionnent. J'ai été surprendre ...

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);
    }
}
 4
Author: thomasfr, 2017-05-23 12:26:36

Les restrictions d'accès 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 de l'instance/classe. Cela va de soi que les classes internes ont également un accès sans entrave aux membres de la classe externe, et la classe externe a un accès sans entrave aux membres de la classe interne.

En mettant une classe dans une autre classe, vous la rendez étroitement liée à l'implémentation, et à tout ce qui fait partie du mise en œuvre devrait avoir accès aux autres parties.

 3
Author: TofuBeer, 2009-11-26 06:27:39

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 que les classes puissent voir le fonctionnement interne de l'autre - ce qui signifie fondamentalement 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'aide de static cela signifie qu'ils ne partageront pas l'état (et, par exemple, new ABC().new XYZ() ne fonctionnera pas, et vous devrez utiliser new ABC.XYZ().
Mais, si c'est le cas, vous devriez vous demander si XYZ devrait vraiment être une classe interne et qu'il mérite peut-être son propre fichier. Parfois, il est logique 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 qui ne sera utile nulle part ailleurs). Mais à environ la moitié du temps, il aurait dû être fait un extérieur de la classe.

 3
Author: abyx, 2009-11-26 06:42:18

Thilo ajouté une bonne réponse pour votre première question: "Comment est-ce possible?". Je souhaite élaborer un peu sur la deuxième question posée: Pourquoi ce comportement est-il autorisé?

Pour commencer, soyons tout à fait clairs que ce comportement n'est pas seulement autorisé pour les 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, l' le modèle est une simplification jusqu'à l'instruction 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 le point.

Pensez à votre corps et à votre cerveau. Si vous injectez de l'héroïne dans votre bras, votre cerveau se défonce. Si la région de l'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 dans l'autre sens et courra vers les collines sans Tu y "penses" deux fois.

Donc, 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 perd leur prétention 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 de regarder comment un Java Iterator habituellement est mettre.

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 fournir un faux sentiment de sécurité pour les nouveaux venus du langage de programmation Java.

 1
Author: Martin Andersson, 2017-05-23 12:02:46

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 classe interne soit privée ou non, la classe externe peut accéder sans aucun problème, tout comme l'accès à ses autres attributs privés(variables).

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}
 -1
Author: MonMoonkey, 2018-04-25 03:13:13

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

 -2
Author: aberrant80, 2009-11-26 05:49:26