128 votes

Est-il possible de rendre statiques les classes internes anonymes en Java ?

En Java, les classes imbriquées peuvent être soit static ou non. S'ils le sont static elles ne contiennent pas de référence au pointeur de l'instance qui les contient (elles ne sont pas non plus appelées classes internes, mais classes imbriquées).

Oublier de faire une classe imbriquée static alors qu'il n'a pas besoin de cette référence peut conduire à des problèmes de garbage collection ou d'analyse d'échappement.

Est-il possible de créer une classe interne anonyme static également ? Ou bien le compilateur s'en rend-il compte automatiquement (ce qui est possible, puisqu'il ne peut y avoir de sous-classes) ?

Par exemple, si je crée un comparateur anonyme, je n'ai presque jamais besoin de la référence à l'extérieur :

  Collections.sort(list, new Comparator<String>(){
       int compare(String a, String b){
          return a.toUpperCase().compareTo(b.toUpperCase());
       }
  }

0 votes

Quels sont les problèmes de "garbage collection ou escape analysis" lorsqu'on oublie de rendre une classe interne statique ? Je pensais qu'il s'agissait uniquement de performances...

17 votes

L'instance de votre classe interne conserve une référence à son instance externe, même si vous n'en avez pas besoin. Cela permet d'éviter la collecte de déchets. Imaginez un objet usine (lourd en ressources) qui crée des instances légères de quelque chose. Une fois que la fabrique a fait son travail (par exemple, pendant le démarrage de l'application), elle pourrait être éliminée, mais cela ne fonctionne que si les choses qu'elle a créées ne sont pas liées.

0 votes

Je sais, ce n'est qu'un exemple, mais comme c'est un exemple récurrent, il faut mentionner que Collections.sort(list, String.CASE_INSENSITIVE_ORDER) fonctionne depuis Java 2, lire, depuis que l'API Collection existe

141voto

Michael Myers Points 82361

Non, vous ne pouvez pas, et non, le compilateur ne peut pas le comprendre. C'est pourquoi FindBugs suggère toujours de remplacer les classes internes anonymes par des classes nommées. static les classes imbriquées si elles n'utilisent pas leur implicite this référence.

Editar: Tom Hawtin - tackline indique que si la classe anonyme est créée dans un contexte statique (par exemple dans la section main ), la classe anonyme est en fait static . Mais le JLS n'est pas d'accord :

Une classe anonyme n'est jamais abstract (§8.1.1.1). Une classe anonyme est toujours une classe interne (§8.1.3) ; elle n'est jamais static (§8.1.1, §8.5.1). Une classe anonyme est toujours implicitement final (§8.1.1.2).

Le glossaire Java de Roedy Green dit que le fait que les classes anonymes soient autorisées dans un contexte statique dépend de l'implémentation :

Si vous voulez déconcerter ceux qui maintiennent votre code, des personnes ont découvert javac.exe autorisera les classes anonymes à l'intérieur de static code init et static méthodes, même si les spécifications du langage disent que les classes anonymes ne sont jamais static . Ces classes anonymes, bien sûr, n'ont pas accès aux champs d'instance de l'objet. Je ne recommande pas de faire cela. Le site fonctionnalité pourrait être retiré à tout moment.

Edit 2 : Le JLS couvre en fait les contextes statiques de manière plus explicite dans §15.9.2 :

Soit C est la classe en cours d'instanciation, et soit i être l'instance en cours de création. Si C est une classe interne, alors i peut avoir une instance immédiatement englobante. L'instance immédiatement englobante de i (§8.1.3) est déterminé comme suit.

  • Si C est une classe anonyme, alors :
    • Si l'expression de création d'instance de classe se produit dans un contexte statique (§8.1.3), alors i n'a pas d'instance immédiatement englobante.
    • Sinon, l'instance immédiatement voisine de i es this .

Ainsi, une classe anonyme dans un contexte statique équivaut grosso modo à une static en ce sens qu'elle ne conserve pas de référence à la classe englobante, même si, techniquement, elle n'est pas une static classe.

19 votes

+1 pour FindBugs - chaque développeur Java devrait l'avoir dans son build.

13 votes

C'est très regrettable, car cela signifie que vous voudrez peut-être éviter cette syntaxe autrement presque concise pour des raisons de performance.

2 votes

JLS 3rd Ed traite le cas des classes internes dans des contextes statiques. Elles ne sont pas statiques au sens de JLS, mais elles le sont au sens de la question.

16voto

Neil Coffey Points 13408

Je pense qu'il y a un peu de confusion dans la nomenclature ici, qui, je l'admets, est trop idiote et confuse.

Quel que soit le nom que vous leur donnez, ces motifs (et quelques variations avec une visibilité différente) sont les suivants tous les possibles, normaux, légaux Java :

public class MyClass {
  class MyClassInside {
  }
}

public class MyClass {
  public static class MyClassInside {
  }
}

public class MyClass {
  public void method() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

public class MyClass {
  public static void myStaticMethod() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

Ils sont pris en compte dans les spécifications du langage (si vous êtes vraiment inquiet, consultez la section 15.9.5.1 pour celui qui se trouve dans la méthode statique).

Mais cette citation est tout simplement faux :

javac.exe autorisera les classes anonymes anonymes à l'intérieur du code d'initialisation statique et et des méthodes statiques, même si la spécification du langage dit que les classes anonymes ne sont jamais statiques

Je pense que l'auteur cité confond les statiques mot-clé avec statique contexte . (Il faut admettre que le JLS est aussi un peu confus à cet égard).

Honnêtement, tous les modèles ci-dessus sont très bien (quel que soit le nom qu'on leur donne : "imbriqué", "intérieur", "anonyme", peu importe...). Vraiment, personne ne va soudainement supprimer cette fonctionnalité dans la prochaine version de Java. Honnêtement !

2 votes

"(Il est vrai que le JLS est également un peu confus à cet égard.)" Vous avez raison. Cela semblait étrange de dire que cela dépend de l'implémentation, mais je ne me souviens pas avoir vu d'erreurs évidentes dans le glossaire Java auparavant. À partir de maintenant, je le prends avec des pincettes.

2 votes

En fait, nous ne parlons d'aucun des modèles. Nous voulons dire que la classe imbriquée anonyme est statique. C'est-à-dire qu'il faut ajouter un "static" entre new y JComponent dans votre troisième exemple.

0 votes

J'ai ajouté une précision à la question initiale pour montrer ce qui est recherché.

15voto

En quelque sorte. Une classe interne anonyme créée dans une méthode statique sera évidemment effectivement statique car il n'y a pas de source pour une classe externe.

Il existe quelques différences techniques entre les classes internes dans des contextes statiques et les classes statiques imbriquées. Si vous êtes intéressé, lisez le JLS 3rd Ed.

0 votes

En fait, je retire ce que j'ai dit ; le JLS n'est pas d'accord. java.sun.com/docs/books/jls/third%5Fedition/html/ : "Une classe anonyme est toujours une classe interne ; elle n'est jamais statique."

1 votes

Statique dans un sens différent de celui de la question.

1 votes

J'ai ajouté une petite clarification.

6voto

Andrew Duffy Points 3574

Les classes internes ne peuvent pas être statiques - une classe statique imbriquée n'est pas une classe interne. Le tutoriel Java en parle ici .

1 votes

J'ai mis à jour la question avec une référence à la nomenclature officielle.

-3voto

Terra Caines Points 962

En ce qui concerne la possibilité de rendre statique une classe interne anonyme en l'appelant dans une méthode statique.

Cela ne supprime pas réellement la référence. Vous pouvez tester cela en essayant de sérialiser la classe anonyme et en ne rendant pas la classe englobante sérialisable.

5 votes

-1 : Création d'une classe anonyme au sein d'une méthode statique en réalité fait supprimer la référence à la classe externe. Vous pouvez tester cela en essayant de sérialiser la classe anonyme et en ne rendant pas la classe englobante sérialisable. (Je viens de le faire.)

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