153 votes

Pourquoi je ne peux pas, nous avons méthode statique dans un intérieur de classe?

Pourquoi ne pouvons-nous pas avoir de méthode statique dans un intérieur de classe ?

Si je le fais à l'intérieur de la classe statique, il fonctionne. Pourquoi ?

114voto

Bill the Lizard Points 147311

Parce que un à l'intérieur de la classe est implicitement associé à une instance de l'extérieur de la classe, il ne peut pas définir toutes les méthodes statiques lui-même. Depuis une statique de la classe imbriquée ne peut pas se référer directement à des variables d'instance ou de méthodes définies dans sa classe englobante, elle peut les utiliser uniquement à travers un objet de référence, il est possible de déclarer des méthodes statiques dans une statique de la classe imbriquée.

49voto

Eddie Points 27755

Il n'y a pas beaucoup de point pour permettre à une méthode statique dans une non-statique à l'intérieur de la classe; comment voulez-vous accès? Vous ne pouvez pas accéder (au moins initialement) un non-statique intérieure instance de classe, sans passer par un extérieur instance de classe. Il n'est pas purement statique de manière à créer un non-statique à l'intérieur de la classe.

Pour l'extérieur de la classe Outer, vous pouvez accéder à une méthode statique test() comme ceci:

Outer.test();

Pour une statique à l'intérieur de la classe Inner, vous pouvez accéder à sa méthode statique innerTest() comme ceci:

Outer.Inner.innerTest();

Toutefois, si Inner n'est pas statique, il n'est purement statique moyen de faire référence à la méthode de innertest. Non statique les classes internes sont liés à une instance spécifique de leur extérieur de la classe. Une fonction est différente à partir d'une constante, d'une référence à l' Outer.Inner.CONSTANT est garanti pour être sans équivoque, de manière qu'un appel de fonction Outer.Inner.staticFunction(); ne l'est pas. Disons que vous avez Inner.staticFunction() qui appelle getState(), qui est définie en Outer. Si vous essayez d'appeler cette fonction statique, vous avez maintenant une référence ambiguë à l'Intérieur de la classe. C'est, sur l'instance de l'intérieur de la classe, vous appelez la fonction statique? C'questions. Voir, il n'y a pas vraiment de manière statique pour faire référence à cette méthode statique, en raison de la référence implicite à l'objet extérieur.

Paul Bellora est exact que la langue concepteurs ont pu avoir permis cela. Ensuite, ils ont soigneusement interdire tout accès à la référence implicite à l'extérieur de la classe dans les méthodes statiques de la non-statique à l'intérieur de la classe. À ce stade, quelle est la valeur à l'intérieur de la classe si vous ne pouvez pas référence à l'extérieur de la classe, à l'exception de statiquement? Et si statique d'accès est bien, alors pourquoi ne pas déclarer l'ensemble de l'intérieur de la classe statique? Si vous faites simplement l'intérieur de la classe elle-même statique, alors vous n'avez aucune référence implicite à l'extérieur de la classe, et vous n'avez plus cette ambiguïté.

Si vous avez réellement besoin de méthodes statiques sur un non-statique à l'intérieur de la classe, alors vous avez probablement besoin de revoir votre conception.

21voto

gustafc Points 13552

J'ai une théorie, qui peut ou peut ne pas être correcte.

Tout d'abord, vous devez savoir quelques choses sur la façon dont les classes internes sont mis en œuvre en Java. Supposons que vous avez cette classe:

class Outer {
    private int foo = 0;
    class Inner implements Runnable {
        public void run(){ foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(); }
}

Lorsque vous compilez, le bytecode généré regardera comme si vous avez écrit quelque chose comme ceci:

class Outer {
    private int foo = 0;
    static class Inner implements Runnable {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public void run(){ this$0.foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(this); }
}

Maintenant, si nous ne nous permettent méthodes statiques et non statiques de classes internes, vous voulez peut-être faire quelque chose comme cela.

class Outer {
    private int foo = 0;
    class Inner {
        public static void incrFoo(){ foo++; }
    }
}

... qui semble assez raisonnable, comme l' Inner classe semble avoir une incarnation par Outer de l'instance. Mais comme nous l'avons vu ci-dessus, le non-statique les classes internes sont vraiment juste de sucre syntaxique pour statique "intérieure" des classes, de sorte que le dernier exemple serait à peu près équivalente à:

class Outer {
    private int foo = 0;
    static class Inner {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public static void incrFoo(){ this$0.foo++; }
    }
}

... ce qui évidemment ne fonctionne pas, depuis this$0 est non-statique. Ce genre de explique pourquoi les méthodes statiques ne sont pas autorisés (bien que vous pourriez faire de l'argument que vous pourrez vous permettre de méthodes statiques tant qu'ils n'ont pas de référence, l'affichage de l'objet), et pourquoi vous ne pouvez pas avoir de non-final champs statiques (il serait contre-intuitif si les cas de non-statique à l'intérieur des classes à partir de différents objets partagés "statique"). Il explique aussi pourquoi finale champs sont autorisées (tant qu'ils ne font pas référence à la englobante de l'objet).

7voto

Don Li Points 311

La seule raison n'est pas "un must", alors pourquoi s'embêter à le soutenir?

Du point de vue syntaxique,il n'y a aucune raison d'interdire un intérieur classe d'avoir des membres statiques. Bien qu'une instance d' Inner est associé à une instance de Outer, il est encore possible d'utiliser Outer.Inner.myStatic de renvoyer un membre statique d' Inner si java décide de le faire.

Si vous avez besoin de partager quelque chose entre toutes les instances de l' Inner, vous pouvez juste mettre en Outer que des membres statiques. Ce n'est pas pire que vous utilisez des membres statiques en InnerOuter pouvez accéder à n'importe quel membre privé d' Inner de toute façon(n'améliore pas l'encapsulation).

Si vous avez besoin de partager quelque chose entre toutes les instances de l' Inner créé par un outer objet,il est plus logique de les mettre en Outer classe de membres ordinaires.

Je ne partage pas l'opinion que "statiques d'une classe imbriquée est à peu près juste une classe de haut niveau". Je pense que c'est mieux pour vraiment considérer l'une statique de la classe imbriquée/intérieur de la classe comme une partie de l'extérieur de la classe, car ils peuvent accéder à l'extérieur de la classe privée des membres. Et les membres de l'extérieur de la classe sont "membres intérieur de la classe". Donc, il n'est pas nécessaire à l'appui de membre statique de l'intérieur de la classe. Ordinaire/membre statique à l'extérieur de la classe suffit.

3voto

Russell Zahniser Points 11176

Réponse courte: Le modèle mental la plupart des programmeurs de la façon la portée des œuvres n'est pas le modèle utilisé par javac. De correspondance la plus intuitive modèle aurait exigé un grand changement dans la façon de javac œuvres.

La principale raison que les membres statiques dans les classes internes sont souhaitables est le cas pour le code de la propreté - un membre statique utilisé uniquement par un intérieur de classe doivent vivre de l'intérieur, plutôt que d'avoir à être placé à l'extérieur de la classe. Considérer:

class Outer {
   int outID;

   class Inner {
      static int nextID;
      int id = nextID++;

      String getID() {
         return outID + ":" + id;
      }
   }
}

Considérons ce qui se passe dans getID() lorsque j'utilise l'identificateur non qualifiés "outID". La portée de cet identificateur apparaît ressemble à quelque chose comme:

Outer -> Inner -> getID()

Ici, encore une fois parce que ce est juste la façon dont javac œuvres, l ' "Extérieur" au niveau de la portée comprend à la fois statique et les membres de l'instance de l'Extérieur. Ceci est source de confusion parce que nous sommes généralement dit de penser à la partie statique d'une classe comme une autre au niveau de la portée:

Outer static -> Outer instance -> instanceMethod()
         \----> staticMethod()

Dans cette façon de penser, bien sûr staticMethod() ne peut voir les membres statiques de l'Extérieur. Mais si c'était comment javac les oeuvres, de la référence à une variable d'instance dans une méthode statique entraînerait un "nom ne peut pas être résolu" erreur. Ce qui se passe vraiment, c'est que ce nom se trouve dans la portée, mais un niveau supplémentaire de contrôle de coups de pied dans les chiffres que le nom a été déclaré dans une instance contexte et est référencé à partir d'un contexte statique.

OK, comment est-ce lié à l'intérieur des classes? Naïvement, nous pensons qu'il n'y a pas de raison que les classes internes ne peuvent pas avoir une statique de la portée, parce que nous sommes imaginer la portée de travailler comme cela:

Outer static -> Outer instance -> Inner instance -> getID()
         \------ Inner static ------^

En d'autres termes, statique déclarations dans l'intérieur de la classe et d'instance de déclarations à l'extérieur de la classe sont à la fois dans le champ d'application au sein de l'instance contexte de l'intérieur de la classe, mais aucune de ces options n'est en fait imbriquée dans l'autre; les deux sont plutôt imbriquée dans la statique de la portée de l'Extérieur.

C'est juste pas comment javac fonctionne - il n'y a qu'un seul niveau de portée pour à la fois statique et les membres de l'instance, et la portée toujours strictement nids. Même l'héritage est mis en œuvre par la copie des déclarations dans la sous-classe plutôt que la ramification et la recherche de la super-classe de la portée.

À l'appui de membres statiques de classes internes javac aurait à scinder la statique et de l'instance d'étendues et de soutien de la ramification et de rejoindre le champ d'application des hiérarchies, ou il aurait pour étendre son booléenne simple "contexte statique" idée de changer de suivre le type de contexte, à tous les niveaux de classe imbriquée dans le champ d'application actuel.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X