web-dev-qa-db-fra.com

Pourquoi Java interdit-il les champs statiques dans les classes internes?

class OuterClass {
 class InnerClass {
  static int i = 100; // compile error
  static void f() { } // compile error
 }
} 

Bien qu'il ne soit pas possible d'accéder au champ statique avec OuterClass.InnerClass.i, si je veux enregistrer quelque chose qui devrait être statique, par exemple le nombre d'objets InnerClass créés, il serait utile de rendre ce champ statique. Alors pourquoi Java interdit-il les champs/méthodes statiques dans les classes internes?

EDIT: Je sais comment rendre le compilateur heureux avec la classe imbriquée statique (ou la classe interne statique), mais ce que je veux savoir, c'est pourquoi Java interdit les champs/méthodes statiques à l'intérieur des classes internes (ou ordinaires classe interne) tant du point de vue de la conception du langage que de la mise en œuvre, si quelqu'un en sait plus.

78
Jichao

L'idée derrière les classes internes est d'opérer dans le contexte de l'instance englobante. D'une manière ou d'une autre, autoriser des variables et des méthodes statiques contredit cette motivation?

8.1.2 Classes internes et instances de clôture

Une classe interne est une classe imbriquée qui n'est pas explicitement ou implicitement déclarée statique. Les classes internes ne peuvent pas déclarer des initialiseurs statiques (§8.7) ou des interfaces membres. Les classes internes ne peuvent pas déclarer de membres statiques, sauf s'il s'agit de champs à constante de compilation (§15.28).

26
Gregory Pakosz

ce que je veux savoir, c'est pourquoi Java interdit les champs/méthodes statiques à l'intérieur des classes internes

Parce que ces classes internes sont des classes internes "d'instance". Autrement dit, ils sont comme un attribut d'instance de l'objet englobant.

Puisqu'il s'agit de classes "instance", cela n'a aucun sens d'autoriser les fonctionnalités static, car static est censé fonctionner sans instance en premier lieu.

C'est comme si vous essayez de créer un attribut statique/instance en même temps.

Prenons l'exemple suivant:

class Employee {
    public String name;
}

Si vous créez deux instances d'employé:

Employee a = new Employee(); 
a.name = "Oscar";

Employee b = new Employee();
b.name = "jcyang";

Il est clair pourquoi chacun a sa propre valeur pour la propriété name, non?

La même chose se produit avec la classe intérieure; chaque instance de classe interne est indépendante de l'autre instance de classe interne.

Donc, si vous essayez de créer un attribut de classe counter, il n'y a aucun moyen de partager cette valeur entre deux instances différentes.

class Employee {
    public String name;
    class InnerData {
        static count; // ??? count of which ? a or b? 
     }
}

Lorsque vous créez l'instance a et b dans l'exemple ci-dessus, quelle serait la valeur correcte pour la variable statique count? Il n'est pas possible de le déterminer, car l'existence de la classe InnerData dépend entièrement de chacun des objets englobants.

C'est pourquoi, lorsque la classe est déclarée comme static, elle n'a plus besoin d'une instance vivante pour vivre elle-même. Maintenant qu'il n'y a pas de dépendance, vous pouvez librement déclarer un attribut statique.

Je pense que cela semble réitératif, mais si vous pensez aux différences entre les attributs d'instance et de classe, cela aura du sens.

43
OscarRyz

En fait, vous pouvez déclarer des champs statiques s'ils sont constants et écrits en temps de compilation.

class OuterClass {
    void foo() {
        class Inner{
            static final int a = 5; // fine
            static final String s = "hello"; // fine
            static final Object o = new Object(); // compile error, because cannot be written during compilation
        }
    }
}
8
vmolchanov

Voici la motivation que je trouve la plus appropriée pour cette "limite": Vous pouvez implémenter le comportement d'un champ statique d'une classe interne comme champ d'instance de l'objet externe; Donc vous n'avez pas besoin champs/méthodes statiques . Le comportement que je veux dire est que toutes les instances de classe interne d'un objet partagent un champ (ou une méthode).

Donc, supposons que vous vouliez compter toutes les instances de classe interne, vous feriez:

public class Outer{
    int nofInner; //this will count the inner class 
                  //instances of this (Outer)object
                  //(you know, they "belong" to an object)
    static int totalNofInner; //this will count all 
                              //inner class instances of all Outer objects
    class Inner {
        public Inner(){
            nofInner++;
            totalNofInner++;
        }
    }
}
5
ianos
  1. classe La séquence d'initialisation est une raison critique.

Comme les classes internes dépendent de l'instance de la classe englobante/externe, la classe externe doit donc être initialisée avant l'initialisation de la classe interne.
Ceci est dit par JLS à propos de l'initialisation de classe. Le point dont nous avons besoin est que la classe T sera initialisée si

  • Un champ statique déclaré par T est utilisé et le champ n'est pas une variable constante.

Donc, si la classe interne a un champ statique accédant, cela provoquera l'initialisation de la classe interne, mais cela ne garantira pas que la classe englobante est initialisée.

  1. Cela violerait certaines règles de base . vous pouvez passer à la dernière section (pour two cases) pour éviter les trucs noob

Une chose à propos de static nestedclass, lorsque certains nested class est static il se comportera comme une classe normale dans tous les sens et il est associé à la classe Outer.

Mais le concept de Inner class/non-staticnested class est qu'il sera associé au instance de la classe externe/englobante. Veuillez noter associé à l'instance pas la classe. L'association avec l'instance signifie clairement que ( d'après le concept de variable d'instance) elle existera à l'intérieur d'une instance et sera différente entre les instances.

Maintenant, lorsque nous créons quelque chose de statique, nous nous attendons à ce qu'il soit initialisé lors du chargement de la classe et devrait être partagé entre toutes les instances. Mais pour être non statique, même les classes internes elles-mêmes ( vous pouvez définitivement oublier l'instance de la classe interne pour l'instant) ne sont pas partagées avec toutes les instances de la classe externe/englobante ( au moins conceptuellement), alors comment pouvons-nous nous attendre à ce que certaines variables de la classe interne soient partagées entre toutes les instances de la classe interne.

Donc si Java nous permet d'utiliser une variable statique à l'intérieur d'une classe imbriquée non statique. Il y aura deux cas .

  • S'il est partagé avec toutes les instances de classe interne, il violera le concept de context of instance (variable d'instance). C'est un NON alors.
  • S'il n'est pas partagé avec toutes les instances, il violera le concept d'être statique. Encore NON.
5
Saif

En termes simples, les classes internes non statiques sont des variables d'instance pour la classe externe, et elles sont créées uniquement lorsqu'une classe externe est créée et qu'un objet de classe externe est créé au moment de l'exécution tandis que les variables statiques sont créées au moment du chargement de la classe. La classe interne non statique est donc une chose d'exécution, c'est pourquoi statique n'est pas la partie d'une classe interne non statique.

REMARQUE: traitez toujours les classes internes comme une variable pour une classe externe, elles peuvent être statiques ou non statiques comme toutes les autres variables.

2
Mannu