web-dev-qa-db-fra.com

Classe imbriquée statique en Java, pourquoi?

Je regardais le code Java pour LinkedList et je me suis rendu compte qu'il utilisait une classe imbriquée statique, Entry.

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

Quelle est la raison d'utiliser une classe imbriquée statique plutôt qu'une classe interne normale?

La seule raison pour laquelle je pouvais penser, c’était que Entry n’avait pas accès aux variables d’instance, donc à partir de OOP), son encapsulation est meilleure.

Mais je pensais qu'il pourrait y avoir d'autres raisons, peut-être la performance. Que pourrait-il être?

Remarque. J'espère que mes termes sont corrects, j'aurais appelé cela une classe interne statique, mais je pense que c'est faux: http://Java.Sun.com/docs/books/tutorial/Java/javaOO/ nested.html

203
David Turner

La page Sun à laquelle vous créez un lien présente des différences essentielles entre les deux:

Une classe imbriquée est membre de sa classe englobante. Les classes imbriquées non statiques (classes internes) ont accès aux autres membres de la classe englobante, même s'ils sont déclarés privés. Les classes imbriquées statiques n'ont pas accès aux autres membres de la classe englobante.
...

Remarque: Une classe imbriquée statique interagit avec les membres d'instance de sa classe externe (et d'autres classes) comme toute autre classe de niveau supérieur. En fait, une classe imbriquée statique est comportementalement une classe de niveau supérieur qui a été imbriquée dans une autre classe de niveau supérieur pour la commodité de l'emballage.

Il n'y a pas besoin de LinkedList.Entry être la classe de niveau supérieur telle quelle seulement utilisée par LinkedList (il existe d'autres interfaces qui ont également des classes imbriquées statiques nommées Entry, telles que comme Map.Entry - même concept). Et comme il n'a pas besoin d'accéder aux membres de LinkedList, il est logique qu'il soit statique - c'est une approche beaucoup plus propre.

Comme Jon Skeet fait remarquer , je pense que si vous utilisez une classe imbriquée, il est préférable de commencer avec une classe statique, puis de décider si elle doit être non statique en se basant sur votre utilisation.

261
matt b

À mon avis, la question devrait être l’inverse chaque fois que vous voyez une classe interne - est-ce que vraiment doit être une classe interne, avec la complexité supplémentaire et l’implicite (plutôt que explicite et plus claire)? , IMO) référence à une instance de la classe contenante?

Remarquez, je suis partial en tant que fan de C # - C # n'a pas l'équivalent des classes internes, bien qu'il ait des types imbriqués. Je ne peux pas dire que j'ai manqué encore les classes intérieures :)

44
Jon Skeet

Il faut prendre en compte ici les problèmes de rétention de mémoire non évidents. Puisqu'une classe interne non statique conserve une référence implicite à sa classe 'externe', si une instance de la classe interne est fortement référencée, l'instance externe est également fortement référencée. Cela peut entraîner des problèmes lorsque la classe externe n'est pas collectée, même si il apparaît que rien n'y fait référence.

26
Leigh

D'une part, les classes internes non statiques ont un champ caché supplémentaire qui pointe vers l'instance de la classe externe. Ainsi, si la classe Entry n'était pas statique, outre qu'elle disposerait d'un accès dont elle n'aurait pas besoin, elle comporterait quatre pointeurs au lieu de trois.

En règle générale, si vous définissez une classe qui est fondamentalement là pour agir comme une collection de données membres, comme une "structure" en C, envisagez de la rendre statique.

10
DavidLG

La classe interne statique est utilisée dans le modèle de générateur. La classe interne statique peut instancier sa classe externe qui n'a qu'un constructeur privé. Vous pouvez donc utiliser la classe interne statique pour instancier la classe externe qui n'a qu'un constructeur privé. Vous ne pouvez pas faire la même chose avec la classe interne car vous devez créer un objet de la classe externe avant d'accéder à la classe interne.

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }

    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}

Cela produira x: 1

7
seenimurugan

la classe imbriquée statique est comme n'importe quelle autre classe externe, car elle n'a pas accès aux membres de la classe externe.

Juste pour des raisons de commodité, nous pouvons regrouper les classes statiques imbriquées dans une classe externe à des fins de lisibilité. Autre que cela, il n'y a pas d'autre cas d'utilisation de classe imbriquée statique.

Exemple pour ce type d’utilisation, vous pouvez trouver dans Android Fichier R.Java (ressources). Le dossier Res de Android contient des mises en forme (contenant des motifs d’écran)), dossier pouvant être dessiné (contenant les images utilisées pour le projet), dossier de valeurs (contenant les constantes de chaîne), etc.

Tous les dossiers font partie du dossier Res, Android L’outil génère un fichier R.Java (ressources) qui contient en interne un grand nombre de classes imbriquées statiques pour chacun de leurs dossiers internes.

Voici l'aspect du fichier R.Java généré dans Android: Ici, ils utilisent uniquement pour la commodité de l'emballage.

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}
7
user1923551

De http://docs.Oracle.com/javase/tutorial/Java/javaOO/whentouse.html :

Utilisez une classe imbriquée (ou une classe interne) non statique si vous souhaitez accéder aux champs et méthodes non publics d'une instance englobante. Utilisez une classe imbriquée statique si vous n'avez pas besoin de cet accès.

6
John29

Exemple simple:

package test;

public class UpperClass {
public static class StaticInnerClass {}

public class InnerClass {}

public static void main(String[] args) {
    // works
    StaticInnerClass stat = new StaticInnerClass();
    // doesn't compile
    InnerClass inner = new InnerClass();
}
}

Si la classe n'est pas statique, la classe ne peut être instanciée que dans une instance de la classe supérieure (donc pas dans l'exemple où main est une fonction statique)

4
Vinze

Une des raisons de statiques vs normales a à voir avec le chargement de classes. Vous ne pouvez pas instancier une classe interne dans le constructeur de son parent.

PS: J'ai toujours compris que "imbriqué" et "interne" étaient interchangeables. Il peut y avoir des nuances subtiles dans les termes, mais la plupart des Java) comprendraient l’un ou l’autre.

2
Mark Renouf

Les classes internes non statiques peuvent entraîner des fuites de mémoire, tandis que les classes internes statiques les protègent. Si la classe externe contient beaucoup de données, cela peut réduire les performances de l'application.

1
The Gun

L'utilisation d'une classe imbriquée statique plutôt que non statique peut économiser des espaces dans certains cas. Par exemple: implémenter un Comparator dans une classe, disons étudiant.

public class Student {
  public static final Comparator<Student> BY_NAME = new ByName();
  private final String name;
  ...
  private static class ByName implements Comparator<Student> {
    public int compare() {...}
  }
}

Ensuite, static garantit que la classe Student ne dispose que d’un seul comparateur, au lieu d’en instancier un nouveau chaque fois qu’une nouvelle instance d’étudiant est créée.

0
JenkinsY

Je ne connais pas les différences de performances, mais comme vous le dites, la classe imbriquée statique ne fait pas partie d'une instance de la classe englobante. Cela semble simplement plus simple de créer une classe imbriquée statique à moins que vous n'ayez vraiment besoin qu'elle soit une classe interne.

C'est un peu comme pourquoi je fais toujours mes variables finales dans Java - si elles ne sont pas finales, je sais qu'il y a quelque chose de drôle avec elles. Si vous utilisez une classe interne au lieu d'une classe statique classe imbriquée, il devrait y avoir une bonne raison.

0
Juri Pakaste