Question

J'ai constaté 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é?

Était-ce utile?

La solution

La classe interne n’est qu’un moyen de séparer proprement certaines fonctionnalités qui appartiennent 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 séparée.
  2. Même si elle fait partie d'une classe séparée, la fonctionnalité est très étroitement liée au fonctionnement de la classe externe.

Compte tenu de ces exigences, les classes internes ont un accès complet à leur classe externe. Comme 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 aux éléments privés.

Autres conseils

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 classe interne est (aux fins du contrôle d’accès) considérée comme faisant partie de la classe contenue. Cela signifie un accès complet à tous les soldats.

Ceci est implémenté en utilisant des méthodes synthétiques protégées par des packages: la classe interne sera compilée dans une classe distincte du même package (ABC $ XYZ). La machine virtuelle Java ne prend pas directement en charge ce niveau d’isolation, de sorte qu’au niveau du bytecode, ABC $ XYZ disposera de méthodes protégées par le paquet 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 les méthodes de la classe englobante peuvent-elles accéder au membre privé d’une classe imbriquée?

Il est indiqué qu'il existe une définition de la portée privée sur JLS - Détermination de l'accessibilité :

  

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

Un modèle d’utilisation important 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 la transmettre au monde extérieur, où l’accès privé sera honoré.

En contradiction avec abyx , déclarant que la classe statique ne modifie pas les restrictions d'accès à la classe englobante, comme indiqué ci-dessous. Les restrictions d'accès entre les classes statiques d'une 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);
    }
}

Les restrictions d'accès sont définies par classe. Il est impossible pour une méthode déclarée dans une classe de ne pas pouvoir accéder à tous les membres d'instance / de classe. Il va sans dire que les classes internes ont également un accès illimité aux membres de la classe externe et que la classe externe a un accès sans restriction aux membres de la classe interne.

En plaçant une classe dans une autre classe, vous la rendez étroitement liée à l'implémentation. Tout ce qui en fait partie devrait avoir accès aux autres parties.

La logique des classes internes est que, si vous créez une classe interne dans une classe externe, c'est parce qu'elles doivent partager un certain nombre de choses, et il est donc logique qu'elles puissent disposer de plus de flexibilité que d'habitude. ; les classes ont.

Si, dans votre cas, cela n'a aucun sens que les classes soient capables de voir le fonctionnement interne des autres - ce qui signifie fondamentalement que la classe interne pourrait tout simplement être devenue une classe régulière, vous pouvez déclarer la classe interne comme < code> classe statique XYZ . Utiliser static signifiera 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 doit vraiment être une classe interne et qu'il 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 utile nulle part ailleurs). Mais environ la moitié du temps, il aurait fallu en faire une classe extérieure.

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

Pour commencer, précisons simplement que ce comportement n'est pas autorisé uniquement 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, le modèle est une simplification jusqu’à l’énoncé suivant: Le code imbriqué a un accès complet au code inclusif - et inversement.

Alors, pourquoi alors? Je pense qu'un exemple illustre mieux le propos.

Pensez à votre corps et à votre cerveau. Si vous injectez de l'héroïne dans votre bras, votre cerveau devient plus 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 va faire tourner votre corps dans l'autre sens et courir vers les collines sans vous "penser". deux fois à ce sujet.

Le cerveau est donc une partie intrinsèque du corps - et étrangement, l’inverse aussi. L'utilisation du contrôle d'accès entre des entités aussi étroitement liées perd leur droit à une 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 probant d’études ultérieures consisterait à 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 créerait un fouillis et pourrait donner un faux sentiment de sécurité aux nouveaux venus du langage de programmation Java.

La classe interne est considérée comme un attribut de la classe externe. Par conséquent, que la variable d’instance de la classe Inner soit privée ou non, la classe Outer peut accéder sans problème, comme pour 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;
}
}

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top