web-dev-qa-db-fra.com

Classe interne Java et classe imbriquée statique

Quelle est la principale différence entre une classe interne et une classe imbriquée statique en Java? La conception/la mise en œuvre joue-t-elle un rôle dans le choix de l’un d’entre eux?

1585
Omnipotent

À partir du Tutoriel Java :

Les classes imbriquées sont divisées en deux catégories: statique et non statique. Les classes imbriquées déclarées statiques sont simplement appelées classes imbriquées statiques. Les classes imbriquées non statiques sont appelées classes internes. 

Les classes imbriquées statiques sont accessibles en utilisant le nom de la classe englobante:

OuterClass.StaticNestedClass

Par exemple, pour créer un objet pour la classe imbriquée statique, utilisez la syntaxe suivante:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

Les objets qui sont des instances d'une classe interne existent dans une instance de la classe externe. Considérez les classes suivantes:

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

Une instance d'InnerClass ne peut exister que dans une instance d'OuterClass et dispose d'un accès direct aux méthodes et aux champs de son instance englobante.

Pour instancier une classe interne, vous devez d'abord instancier la classe externe. Ensuite, créez l'objet interne dans l'objet externe avec cette syntaxe:

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

voir: Tutoriel Java - Classes imbriquées

Pour être complet, notez qu’il existe également une chose telle que une classe interne sans une instance englobante :

class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

new A() { ... } est ici une classe inner définie dans un contexte statique et n'a pas d'instance englobante.

1564
Martin

Le tutoriel Java dit :

Terminologie: Les classes imbriquées sont divisées en deux catégories: statique et non statique. Les classes imbriquées déclarées statiques sont simplement appelées classes imbriquées statiques. Les classes imbriquées non statiques sont appelées classes internes.

En langage courant, les termes "imbriqué" et "interne" sont utilisés indifféremment par la plupart des programmeurs, mais j'utiliserai le terme correct "classe imbriquée" qui couvre à la fois les propriétés interne et statique.

Les classes peuvent être imbriquées à l'infini , par exemple. la classe A peut contenir la classe B, qui contient la classe C, qui contient la classe D, etc. Toutefois, plusieurs niveaux d'imbrication de classe sont rares, car leur conception est généralement mauvaise.

Vous pouvez créer une classe imbriquée pour trois raisons:

  • organisation: il semble parfois plus judicieux de trier une classe dans l'espace de noms d'une autre classe, surtout lorsqu'elle ne sera pas utilisée dans un autre contexte
  • access: les classes imbriquées ont un accès spécial aux variables/champs de leurs classes les contenant (précisément les variables/champs dépendent du type de classe imbriquée, qu'elle soit interne ou statique).
  • commodité: avoir à créer un nouveau fichier pour chaque nouveau type est gênant, surtout lorsque le type ne sera utilisé que dans un seul contexte

Il existe quatre types de classe imbriquée en Java . En bref, ils sont:

  • classe statique : déclaré en tant que membre statique d'une autre classe
  • classe interne : déclarée en tant que membre d'instance d'une autre classe
  • classe interne locale : déclarée à l'intérieur d'une méthode d'instance d'une autre classe
  • classe interne anonyme : semblable à une classe interne locale, mais écrite sous la forme d'une expression renvoyant un objet unique.

Laissez-moi élaborer plus en détail.


Classes statiques

Les classes statiques sont le type le plus facile à comprendre car elles n'ont rien à voir avec les instances de la classe contenante.

Une classe statique est une classe déclarée en tant que membre statique d'une autre classe. Tout comme les autres membres statiques, une telle classe n’est en réalité qu’un mécanisme de suspension qui utilise la classe contenante comme espace de nom , par exemple la classe , Goat déclaré comme membre statique de la classe Rhino dans le package pizza est connu sous le nom pizza.Rhino.Goat .

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

Franchement, les classes statiques sont une fonctionnalité plutôt inutile, car les classes sont déjà divisées en espaces de noms par packages. La seule vraie raison concevable de créer une classe statique est qu'une telle classe ait accès aux membres statiques privés de sa classe contenante, mais j'estime qu'il s'agit d'une justification assez boiteuse pour que la fonction de classe statique existe.


Classes intérieures

Une classe interne est une classe déclarée en tant que membre non statique d'une autre classe:

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

Comme avec une classe statique, la classe interne est qualifiée de qualifiée par son nom de classe contenant, pizza.Rhino.Goat , mais à l'intérieur de la classe contenante, elle peut être connue par sa simple prénom. Cependant, chaque instance d'une classe interne est liée à une instance particulière de la classe qui la contient: ci-dessus, le chèvre créé dans jerry , est implicitement liée à l’instance de Rhino this dans jerry . Sinon, nous rendons explicite l'instance associée Rhino lorsque nous instancions Goat :

Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();

(Notez que vous vous référez au type interne simplement Chèvre dans l'étrange nouvelle syntaxe : Java en déduit le contenant le type de la partie rhino . Et oui nouveau rhino.Goat () aurait eu plus de sens pour moi aussi.)

Alors qu'est-ce que cela nous gagne? Eh bien, l'instance de classe interne a accès aux membres d'instance de l'instance de classe contenue. Ces membres d'instance englobants sont référencés dans la classe interne via uniquement leurs noms simples, et non via this ( this dans la classe interne fait référence à l'instance de la classe interne, pas à l'instance de la classe contenante associée):

public class Rhino {

    private String barry;

    public class Goat {
        public void colin() {
            System.out.println(barry);
        }
    }
}

Dans la classe interne, vous pouvez faire référence à this de la classe contenante en tant que Rhino.this , et vous pouvez utiliser this pour faire référence à ses membres, par exemple Rhino.this.barry .


Classes internes locales

Une classe interne locale est une classe déclarée dans le corps d'une méthode. Une telle classe n'est connue que dans sa méthode contenant; elle ne peut donc être instanciée et ses membres ne doivent être accédés que dans sa méthode contenant. L'avantage est qu'une instance de classe interne locale est liée à et peut accéder aux variables locales finales de la méthode qui la contient. Lorsque l'instance utilise un dernier local de la méthode qui la contient, la variable conserve la valeur qu'elle détenait au moment de la création de l'instance, même si la variable est hors de portée (il s'agit en réalité de la version brute et limitée de Java de la clôture).

Comme une classe interne locale n'est ni le membre d'une classe ni d'un package, elle n'est pas déclarée avec un niveau d'accès. (Soyez clair, cependant, que ses propres membres ont des niveaux d'accès similaires à ceux d'une classe normale.)

Si une classe interne locale est déclarée dans une méthode d'instance, une instanciation de la classe interne est liée à l'instance détenue par la méthode contenant this au moment de la création de l'instance, et les membres d'instance de la classe contenante sont donc accessibles comme dans une classe interne d'instance. Une classe interne locale est instanciée simplement via son nom, , par exemple une classe interne locale Cat est instancié comme new Cat () , pas new this.Cat () comme on pourrait s'y attendre.


Classes intérieures anonymes

Une classe interne anonyme est un moyen pratique d'écrire une classe interne locale pour la syntaxe. Le plus souvent, une classe interne locale est instanciée au plus une fois à chaque fois que sa méthode est exécutée. Ce serait donc bien si nous pouvions combiner la définition de la classe interne locale et son instanciation unique en une seule forme de syntaxe commode, et ce serait également agréable si nous n’avions pas à inventer un nom pour la classe (le moins inutile nom que votre code contient, le mieux). Une classe interne anonyme permet ces deux choses:

new *ParentClassName*(*constructorArgs*) {*members*}

C'est une expression renvoyant une nouvelle instance d'une classe sans nom qui s'étend ParentClassName . Vous ne pouvez pas fournir votre propre constructeur. au lieu de cela, on fournit implicitement ce qui appelle simplement le super constructeur, de sorte que les arguments fournis doivent correspondre au super constructeur. (Si le parent contient plusieurs constructeurs, le plus "simple" est appelé, "le plus simple", déterminé par un ensemble assez complexe de règles qu'il est inutile d'apprendre en détail - il suffit de faire attention à ce que NetBeans ou Eclipse vous disent.)

Alternativement, vous pouvez spécifier une interface à implémenter:

new *InterfaceName*() {*members*}

Une telle déclaration crée une nouvelle instance d'une classe sans nom qui étend Object et implémente NomName . Encore une fois, vous ne pouvez pas fournir votre propre constructeur; dans ce cas, Java fournit implicitement un constructeur sans argument, sans action (il n'y aura donc jamais d'arguments de constructeur dans ce cas).

Même si vous ne pouvez pas attribuer un constructeur à une classe interne anonyme, vous pouvez néanmoins effectuer la configuration de votre choix à l'aide d'un bloc d'initialisation (un bloc {} placé en dehors de toute méthode).

Indiquez clairement qu'une classe interne anonyme est simplement un moyen moins flexible de créer une classe interne locale avec une instance. Si vous voulez une classe interne locale qui implémente plusieurs interfaces ou qui implémente des interfaces tout en développant une classe autre que Object ou qui spécifie son propre constructeur, vous devez créer un nom local appelé classe intérieure.

570
Jegschemesch

Je ne pense pas que la vraie différence soit devenue claire dans les réponses ci-dessus. 

D'abord pour bien comprendre les termes: 

  • Une classe imbriquée est une classe contenue dans une autre classe au niveau du code source.
  • C'est statique si vous le déclarez avec le statique modificateur.
  • Une classe imbriquée non statique est appelée classe interne. (Je reste avec la classe imbriquée non statique.)

La réponse de Martin est juste jusqu'à présent. Cependant, la question est la suivante: quel est le but de déclarer une classe imbriquée statique ou non?

Vous utilisez classes imbriquées statiques si vous souhaitez simplement conserver vos classes ensemble si elles appartiennent topiquement ensemble ou si la classe imbriquée est exclusivement utilisée dans la classe englobante. Il n'y a pas de différence sémantique entre une classe imbriquée statique et toutes les autres classes.

Les classes imbriquées non statiques sont une autre bête. Semblables aux classes internes anonymes, ces classes imbriquées sont en réalité des fermetures. Cela signifie qu'ils capturent leur portée environnante et leur instance englobante et la rendent accessible. Peut-être qu'un exemple clarifiera cela. Voir ce bout d'un conteneur:

public class Container {
    public class Item{
        Object data;
        public Container getContainer(){
            return Container.this;
        }
        public Item(Object data) {
            super();
            this.data = data;
        }

    }

    public static Item create(Object data){
        // does not compile since no instance of Container is available
        return new Item(data);
    }
    public Item createSubItem(Object data){
        // compiles, since 'this' Container is available
        return new Item(data);
    }
}

Dans ce cas, vous voulez avoir une référence d'un élément enfant au conteneur parent. En utilisant une classe imbriquée non statique, cela fonctionne sans aucun travail. Vous pouvez accéder à l'instance englobante de Container avec la syntaxe Container.this.

Plus d'explications hardcore suivantes:

Si vous regardez les bytecodes Java générés par le compilateur pour une classe imbriquée (non statique), cela peut devenir encore plus clair:

// class version 49.0 (49)
// access flags 33
public class Container$Item {

  // compiled from: Container.Java
  // access flags 1
  public INNERCLASS Container$Item Container Item

  // access flags 0
  Object data

  // access flags 4112
  final Container this$0

  // access flags 1
  public getContainer() : Container
   L0
    LINENUMBER 7 L0
    ALOAD 0: this
    GETFIELD Container$Item.this$0 : Container
    ARETURN
   L1
    LOCALVARIABLE this Container$Item L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 1
  public <init>(Container,Object) : void
   L0
    LINENUMBER 12 L0
    ALOAD 0: this
    ALOAD 1
    PUTFIELD Container$Item.this$0 : Container
   L1
    LINENUMBER 10 L1
    ALOAD 0: this
    INVOKESPECIAL Object.<init>() : void
   L2
    LINENUMBER 11 L2
    ALOAD 0: this
    ALOAD 2: data
    PUTFIELD Container$Item.data : Object
    RETURN
   L3
    LOCALVARIABLE this Container$Item L0 L3 0
    LOCALVARIABLE data Object L0 L3 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

Comme vous pouvez le constater, le compilateur crée un champ masqué Container this$0. Ceci est défini dans le constructeur qui a un paramètre supplémentaire de type Container pour spécifier l'instance englobante. Vous ne pouvez pas voir ce paramètre dans le source mais le compilateur le génère implicitement pour une classe imbriquée. 

L'exemple de Martin

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

serait ainsi compilé à un appel de quelque chose comme (en bytecodes)

new InnerClass(outerObject)

Par souci d'exhaustivité:

Une classe anonyme est un exemple parfait d'une classe imbriquée non statique à laquelle aucun nom n'est associé et ne peut pas être référencée ultérieurement.

131
jrudolph

Je pense qu'aucune des réponses ci-dessus ne vous explique la différence réelle entre une classe imbriquée et une classe imbriquée statique en termes de conception d'application: 

OverView

Une classe imbriquée peut être non statique ou statique et dans chaque cas est une classe définie dans une autre classe . Une classe imbriquée ne devrait exister que pour servir sa classe englobante , si une classe imbriquée est utile pour les autres classes (pas seulement la classe englobante), devrait être déclarée comme classe de niveau supérieur.

Différence

La classe imbriquée non statique : est implicitement associée à l'instance englobante de la classe contenante, cela signifie qu'il est possible d'appeler des méthodes et des variables d'accès de l'instance englobante. Une utilisation courante d'une classe imbriquée non statique consiste à définir une classe d'adaptateur.

Classe imbriquée statique : ne peut pas accéder à une instance de classe englobante ni y invoquer des méthodes; elle doit donc être utilisée lorsque la classe imbriquée ne nécessite pas l'accès à une instance de la classe englobante. Une utilisation courante de la classe imbriquée statique consiste à implémenter des composants de l'objet externe.

Conclusion

Ainsi, la principale différence entre les deux, du point de vue de la conception, est la suivante: la classe imbriquée non statique peut accéder à l'instance de la classe conteneur, alors que static ne peut pas.

88
aleroot

En termes simples, nous avons besoin de classes imbriquées principalement parce que Java ne fournit pas de fermetures.

Les classes imbriquées sont des classes définies dans le corps d'une autre classe englobante. Ils sont de deux types - statique et non statique.

Ils sont traités comme des membres de la classe englobante. Par conséquent, vous pouvez spécifier l'un des quatre spécificateurs d'accès - private, package, protected, public. Nous n'avons pas ce luxe avec des classes de haut niveau, qui ne peuvent être déclarées que public ou package-private.

Inner classes Les classes non-stack ont ​​accès aux autres membres de la classe supérieure, même si elles sont déclarées privées alors que les classes imbriquées statiques n'ont pas accès aux autres membres de la classe.

public class OuterClass {
    public static class Inner1 {
    }
    public class Inner2 {
    }
}

Inner1 est notre classe interne statique et Inner2 est notre classe interne qui n'est pas statique. La différence clé entre eux, vous ne pouvez pas créer une instance Inner2 sans un Outer où vous pouvez créer un objet Inner1 indépendamment.

Quand utiliseriez-vous la classe intérieure?

Pensez à une situation où Class A et Class B sont liés, Class B doit accéder aux membres Class A et Class B est lié uniquement à Class A. Les classes intérieures entrent en scène.

Pour créer une instance de classe interne, vous devez créer une instance de votre classe externe.

OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();

ou

OuterClass.Inner2 inner = new OuterClass().new Inner2();

Quand utiliseriez-vous la classe Inner statique?

Vous définissez une classe interne statique lorsque vous savez qu’elle n’a aucune relation avec l’instance de la classe englobante/top. Si votre classe interne n'utilise pas de méthodes ou de champs de la classe externe, il ne s'agit que d'un gaspillage d'espace. Rendez-le donc statique.

Par exemple, pour créer un objet pour la classe imbriquée statique, utilisez la syntaxe suivante:

OuterClass.Inner1 nestedObject = new OuterClass.Inner1();

L'avantage d'une classe imbriquée statique est qu'elle n'a pas besoin d'un objet de la classe contenant/top class pour fonctionner. Cela peut vous aider à réduire le nombre d'objets créés par votre application lors de l'exécution.

31
Thalaivar

Je pense que la convention généralement suivie est la suivante:

  • classe statique au sein d'une classe de niveau supérieur est un classe imbriquée
  • classe non statique au sein d'une classe de niveau supérieur est une classe intérieure, qui, en outre,.
    • classe locale - classes nommées déclarées à l'intérieur d'un bloc comme une méthode ou un corps de constructeur
    • classe anonyme - classes non nommées dont les instances sont créées dans des expressions et des instructions

Cependant, peu d'autres points à retenir sont:

  • Les classes de niveau supérieur et la classe imbriquée statique sont sémantiquement identiques, sauf que dans le cas d'une classe imbriquée statique, elle peut faire une référence statique aux champs/méthodes statiques privés de sa classe Outer [parent] et inversement.

  • Les classes internes ont accès aux variables d'instance de l'instance englobante de la classe Outer [parent]. Cependant, toutes les classes internes ne disposent pas d'instances englobantes, par exemple, les classes internes dans des contextes statiques, comme une classe anonyme utilisée dans un bloc d'initialiseur statique, n'en ont pas.

  • La classe anonyme étend par défaut la classe parent ou implémente l'interface parent. Il n'y a pas d'autre clause pour étendre une autre classe ou implémenter d'autres interfaces. Alors,

    • new YourClass(){}; signifie class [Anonymous] extends YourClass {}
    • new YourInterface(){}; signifie class [Anonymous] implements YourInterface {}

Je pense que la plus grande question qui reste ouverte, laquelle utiliser et quand? Cela dépend principalement du scénario auquel vous faites face, mais lire la réponse donnée par @jrudolph peut vous aider à prendre une décision.

26
sactiw

Voici les principales différences et similitudes entre la classe interne Java et la classe imbriquée statique.

J'espère que ça aide!

Classe intérieure

  • Peut accéder à la classe externe à la fois l'instance et statique méthodes et champs
  • Associé à une instance de classe englobante pour l'instancier, il faut d'abord une instance de classe externe (note nouvelle place du mot clé):

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
    
  • Impossible définir les membres statiques lui-même

  • _ {Impossible avoir la déclaration Classe ou interface

Classe imbriquée statique

  • Accès impossible classe externe instance méthodes ou champs

  • Non associé à aucune instance de la classe englobante Donc, pour l'instancier:

    OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
    

Similitudes

  • Les deux classes internes peuvent accéder même à champs et méthodes privés de classe externe
  • Les classes externes ont également accès à champs et méthodes privés de classes internes
  • Les deux classes peuvent avoir un modificateur d'accès privé, protégé ou public

Pourquoi utiliser des classes imbriquées?

Selon la documentation Oracle, il existe plusieurs raisons ( documentation complète ):

  • C'est une façon de regrouper logiquement des classes qui ne sont utilisées qu'à un seul endroit: Si une classe n'est utile qu'à une seule autre classe, il est logique de l'intégrer dans cette classe et de conserver les deux ensemble. L'imbrication de telles "classes d'assistance" rend leur paquet plus rationalisé.

  • Cela augmente l'encapsulation:} Considérons deux classes de niveau supérieur, A et B, où B a besoin d'accéder aux membres de A qui seraient autrement déclarés privés. En cachant la classe B dans la classe A, les membres de A peuvent être déclarés privés et B peut y accéder. De plus, B lui-même peut être caché du monde extérieur.

  • Cela peut conduire à un code plus lisible et maintenable: _ L'imbrication de petites classes au sein de classes de niveau supérieur place le code plus près de son utilisation.

26
Behzad Bahmanyar

Classe imbriquée: classe dans la classe

Les types:

  1. Classe imbriquée statique
  2. Classe imbriquée non statique [Classe intérieure]

Différence:

Classe imbriquée non statique [Classe intérieure]

Dans une classe imbriquée non statique, un objet de la classe interne existe dans l'objet de la classe externe. Ainsi, le membre de données de la classe externe est accessible à la classe interne. Donc, pour créer un objet de classe interne, nous devons d'abord créer un objet de classe externe.

outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass(); 

Classe imbriquée statique

Dans la classe statique imbriquée, l'objet de la classe interne n'a pas besoin d'objet de la classe externe, car le mot "statique" indique qu'il n'est pas nécessaire de créer un objet.

class outerclass A {
    static class nestedclass B {
        static int x = 10;
    }
}

Si vous voulez accéder à x, alors écrivez la méthode inside suivante

  outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);
15
tejas

Il existe une subtilité concernant l’utilisation de classes statiques imbriquées qui pourrait être utile dans certaines situations.

Alors que les attributs statiques sont instanciés avant que la classe ne soit instanciée via son constructeur, les attributs statiques à l'intérieur des classes statiques imbriquées ne semblent être instanciés qu'après que le constructeur de la classe .__ ait été appelé, ou du moins pas après les attributs. sont d'abord référencés, même s'ils sont marqués comme "final".

Considérons cet exemple:

public class C0 {

    static C0 instance = null;

    // Uncomment the following line and a null pointer exception will be
    // generated before anything gets printed.
    //public static final String outerItem = instance.makeString(98.6);

    public C0() {
        instance = this;
    }

    public String makeString(int i) {
        return ((new Integer(i)).toString());
    }

    public String makeString(double d) {
        return ((new Double(d)).toString());
    }

    public static final class nested {
        public static final String innerItem = instance.makeString(42);
    }

    static public void main(String[] argv) {
        System.out.println("start");
        // Comment out this line and a null pointer exception will be
        // generated after "start" prints and before the following
        // try/catch block even gets entered.
        new C0();
        try {
            System.out.println("retrieve item: " + nested.innerItem);
        }
        catch (Exception e) {
            System.out.println("failed to retrieve item: " + e.toString());
        }
        System.out.println("finish");
    }
}

Même si 'imbriqué' et 'innerItem' sont tous deux déclarés comme 'statiques finales'. le paramètre de nested.innerItem n’a lieu qu’après l’instanciation de la classe (ou au moins pas avant que l’élément statique imbriqué ait été référencé pour la première fois), comme vous pouvez le constater par vous-même en commentant et décommenter les lignes auxquelles je me réfère, ci-dessus. La même chose ne vaut pas True pour 'outerItem'.

Au moins c'est ce que je vois dans Java 6.0.

11
HippoMan

L'instance de la classe interne est créée lors de la création de l'instance de la classe externe. Par conséquent, les membres et les méthodes de la classe interne ont accès aux membres et aux méthodes de l'occurrence (objet) de la classe externe. Lorsque l'instance de la classe externe sort de la portée, les instances de la classe interne cessent également d'exister.

La classe imbriquée statique n'a pas d'instance concrète. Il vient d'être chargé lorsqu'il est utilisé pour la première fois (tout comme les méthodes statiques). C'est une entité complètement indépendante, dont les méthodes et les variables n'ont aucun accès aux instances de la classe externe.

Les classes imbriquées statiques ne sont pas couplées à l'objet externe, elles sont plus rapides et ne prennent pas de mémoire en tas/pile, car il n'est pas nécessaire de créer une instance de cette classe. Par conséquent, la règle empirique est d'essayer de définir une classe imbriquée statique, avec une portée aussi limitée que possible (privé> = classe> = protégée> = publique), puis de la convertir en classe interne (en supprimant l'identifiant "statique") la portée, si c'est vraiment nécessaire.

11
rmaruszewski

Je ne pense pas qu'il y ait grand chose à ajouter ici, la plupart des réponses expliquent parfaitement les différences entre les classes imbriquées statiques et les classes Inner. Cependant, tenez compte du problème suivant lors de l'utilisation de classes imbriquées par rapport à des classes internes. Comme mentionné dans quelques réponses, les classes internes ne peuvent pas être instanciées sans une instance de leur classe englobante, ce qui signifie qu'ellesTIENNENTa un pointeur vers l'instance de leur classe englobante qui peut mener débordement de mémoire ou exception de débordement de pile car le CPG ne pourra pas récupérer les classes englobantes même si elles ne sont plus utilisées. Pour que cela soit clair, vérifiez le code suivant: 

public class Outer {


    public  class Inner {

    }


    public Inner inner(){
        return new Inner();
    }

    @Override
    protected void finalize() throws Throwable {
    // as you know finalize is called by the garbage collector due to destroying an object instance
        System.out.println("I am destroyed !");
    }
}


public static void main(String arg[]) {

    Outer outer = new Outer();
    Outer.Inner inner = outer.new Inner();

    // out instance is no more used and should be garbage collected !!!
    // However this will not happen as inner instance is still alive i.e used, not null !
    // and outer will be kept in memory until inner is destroyed
    outer = null;

    //
    // inner = null;

    //kick out garbage collector
    System.gc();

}

Si vous supprimez le commentaire sur // inner = null;, le programme sortira " Je suis détruit! ", mais en gardant ce commentaire, cela ne le sera pas.
La raison en est que l'instance interne blanche est toujours référencée, mais GC ne peut pas la collecter et, comme elle référence (a un pointeur sur) l'instance externe, elle ne l'est pas non plus. Avoir assez de ces objets dans votre projet et peut manquer de mémoire.
Comparé aux classes internes statiques qui ne contiennent pas de point relatif à une instance de classe interne car elle n'est pas liée à une instance, mais à une classe. Le programme ci-dessus peut imprimer " Je suis détruit! " si vous rendez la classe Inner statique et instanciée avec Outer.Inner i = new Outer.Inner(); 

10
Adelin

Dans le cas de la création d'une instance, l'instance de la classe interne non Static est créée avec la référence de Object de la classe externe dans laquelle elle est définie. Ceci Signifie qu'il a une instance englobante . Mais l'instance de la classe interne statique est créée avec la référence de la classe externe, pas avec la référence de l'objet de la classe externe. Cela signifie qu'il n'a pas d'instance.

Par exemple:

class A
{
  class B
  {
    // static int x; not allowed here…..    
  }
  static class C
  {
    static int x; // allowed here
  }
}

class Test
{
  public static void main(String… str)
  {
    A o=new A();
    A.B obj1 =o.new B();//need of inclosing instance

    A.C obj2 =new A.C();

    // not need of reference of object of outer class….
  }
}
10
Ankit Jain

Les termes sont utilisés indifféremment. Si vous voulez être vraiment pédant à ce sujet, vous pouvez pouvez définir "classe imbriquée" pour faire référence à une classe interne statique, qui ne possède aucune instance englobante. Dans le code, vous pourriez avoir quelque chose comme ça:

public class Outer {
    public class Inner {}

    public static class Nested {}
}

Ce n'est pas vraiment une définition largement acceptée cependant.

8
Daniel Spiewak

La classe imbriquée est un terme très général: toute classe qui n'est pas le niveau le plus élevé est une classe imbriquée . Une classe interne est une classe imbriquée non statique . Joseph Darcy a écrit une très belle explication à propos de , Membre et classes de premier niveau .

8
Wouter Coekaerts

Apprenant ciblé novice en Java et/ou classes imbriquées 

Les classes imbriquées peuvent être:
1. Classes imbriquées statiques.
2. Classes imbriquées non statiques. (également appelé Inner classes ) => S'il vous plaît rappelez-vous ceci


1.Inner classes
Exemple:

class OuterClass  {
/*  some code here...*/
     class InnerClass  {  }
/*  some code here...*/
}


Les classes internes sont des sous-ensembles de classes imbriquées:

  • la classe interne est un type spécifique de classe imbriquée
  • les classes internes sont des sous-ensembles de classes imbriquées
  • Vous pouvez dire qu'une classe intérieure est également une classe imbriquée, mais vous pouvezPASdire qu'une classe imbriquée est également une classe intérieure

Spécialité de classe intérieure:

  • l’instance d’une classe interne a accès à tous des membres de la classe externe, même ceux qui sont marqués «privé»


2. Classes imbriquées statiques:
Exemple:

class EnclosingClass {
  static class Nested {
    void someMethod() { System.out.println("hello SO"); }
  }
}

Cas 1: Instanciation d'une classe imbriquée statique à partir d'une classe non englobante

class NonEnclosingClass {

  public static void main(String[] args) {
    /*instantiate the Nested class that is a static
      member of the EnclosingClass class:
    */

    EnclosingClass.Nested n = new EnclosingClass.Nested(); 
    n.someMethod();  //prints out "hello"
  }
}

Cas 2: Instanciation d'une classe imbriquée statique à partir d'une classe englobante

class EnclosingClass {

  static class Nested {
    void anotherMethod() { System.out.println("hi again"); } 
  }

  public static void main(String[] args) {
    //access enclosed class:

    Nested n = new Nested(); 
    n.anotherMethod();  //prints out "hi again"
  }

}

Spécialité des classes statiques:

  • La classe interne statique aurait uniquement accès aux membres statiques de la classe externe et n'aurait aucun accès aux membres non statiques.

Conclusion:
Question: Quelle est la principale différence entre une classe interne et une classe imbriquée statique en Java?
Réponse: il suffit de passer en revue les spécificités de chaque classe susmentionnée.

7
VdeX

Ummm ... une classe interne IS une classe imbriquée ... voulez-vous dire une classe anonyme et une classe interne?

Edit: Si vous vouliez réellement dire interne vs anonyme ... une classe interne est simplement une classe définie dans une classe telle que:

public class A {
    public class B {
    }
}

Alors qu’une classe anonyme est une extension d’une classe définie anonymement, aucune «classe réelle» n’est définie, comme dans:

public class A {
}

A anon = new A() { /* you could change behavior of A here */ };

Autre édition:

Wikipedia affirme qu'il y a une différence en Java, mais cela fait 8 ans que je travaille avec Java, et c'est la première fois que j'entends une telle distinction ... sans mentionner qu'il n'y a aucune référence à l'appui de cette affirmation. ... en bout de ligne, une classe interne est une classe définie dans une classe (statique ou non), et imbriqué est simplement un autre terme qui signifie la même chose.

Il existe une différence subtile entre les classes imbriquées statiques et non statiques ... essentiellement, les classes internes non statiques ont un accès implicite aux champs d'instance et aux méthodes de la classe englobante (elles ne peuvent donc pas être construites dans un contexte statique, ce sera un compilateur Erreur). Les classes imbriquées statiques, en revanche, n'ont pas d'accès implicite aux méthodes et aux champs d'instance, et PEUVENT être construites dans un contexte statique.

7
Mike Stone

Inner class et nested static class en Java sont des classes déclarées dans une autre classe, appelée classe de niveau supérieur en Java. Dans la terminologie Java, si vous déclarez une classe imbriquée statique, elle sera appelée classe statique imbriquée en Java, tandis que la classe imbriquée non statique est simplement appelée Classe intérieure. 

Qu'est-ce que Inner Class en Java?

Toute classe qui n'est pas de niveau supérieur ou déclarée dans une autre classe est appelée classe imbriquée. En dehors de ces classes imbriquées, les classes déclarées non statiques sont appelées classe Inner en Java. il existe trois types de classe Inner en Java:

1) Classe interne locale - est déclarée dans un bloc de code ou une méthode.
2) Classe interne anonyme: classe qui n'a pas de nom à référencer et qui est initialisée au même endroit où elle est créée.
3) Membre de la classe interne - est déclaré membre non statique de la classe externe.

public class InnerClassTest {
    public static void main(String args[]) {      
        //creating local inner class inside method i.e. main() 
        class Local {
            public void name() {
                System.out.println("Example of Local class in Java");

            }
        }      
        //creating instance of local inner class
        Local local = new Local();
        local.name(); //calling method from local inner class

        //Creating anonymous inner class in Java for implementing thread
        Thread anonymous = new Thread(){
            @Override
            public void run(){
                System.out.println("Anonymous class example in Java");
            }
        };
        anonymous.start();

        //example of creating instance of inner class
        InnerClassTest test = new InnerClassTest();
        InnerClassTest.Inner inner = test.new Inner();
        inner.name(); //calling method of inner class
    }

     //Creating Inner class in Java
    private class Inner{
        public void name(){
            System.out.println("Inner class example in Java");
        }
    }
}

Qu'est-ce qu'une classe statique imbriquée en Java?

La classe statique imbriquée est une autre classe déclarée à l'intérieur d'une classe en tant que membre et rendue statique. La classe statique imbriquée est également déclarée comme membre de la classe externe et peut être rendue privée, publique ou protégée comme n'importe quel autre membre. L'un des principaux avantages de la classe statique imbriquée par rapport à la classe interne est que l'instance de la classe statique imbriquée n'est liée à aucune instance englobante de la classe externe. Vous n'avez également besoin d'aucune instance de classe externe pour créer une instance de classe statique imbriquée en Java.

1) Il peut accéder à membres de données statiques de la classe externe, y compris privé.
2) La classe imbriquée statique ne peut pas accéder à membre de données non statique (instance) ou méthode.

public class NestedStaticExample {
    public static void main(String args[]){  
        StaticNested nested = new StaticNested();
        nested.name();
    }  
    //static nested class in Java
    private static class StaticNested{
        public void name(){
            System.out.println("static nested class example in Java");
        }
    }
}

Ref: Classe interne et classe statique imbriquée en Java avec Example

6
roottraveller

Lorsque nous déclarons une classe membre statique dans une classe, elle est appelée classe imbriquée de niveau supérieur ou classe imbriquée statique. Cela peut être démontré comme ci-dessous: 

class Test{
    private static int x = 1;
        static class A{
        private static int y = 2;
        public static int getZ(){
            return B.z+x;
        }
    }
    static class B{
        private static int z = 3;
        public static int getY(){
            return A.y;
        }
    }
}

class TestDemo{
     public static void main(String[] args){
        Test t = new Test();
        System.out.println(Test.A.getZ());
        System.out.println(Test.B.getY());
    }
}

Lorsque nous déclarons une classe membre non statique dans une classe, elle est appelée classe interne. La classe intérieure peut être démontrée comme ci-dessous: 

    class Test{
        private int i = 10;
        class A{
            private int i =20;
            void display(){
            int i = 30;
            System.out.println(i);
            System.out.println(this.i);
            System.out.println(Test.this.i);
        }
    }
}
5
Pankti

Je pense que les gens ici devraient remarquer à Poster que: La classe de nids statiques ne représente que la première classe interne ..

 public static class A {} //ERROR

 public class A {
     public class B {
         public static class C {} //ERROR
     }
 }

 public class A {
     public static class B {} //COMPILE !!!

 }

Donc, résumons, la classe statique ne dépend pas de la classe qu’elle contient. Donc, ils ne peuvent pas en classe normale. (parce que la classe normale a besoin d'une instance).

5
hqt

Voici un exemple de static nested class et inner class:

OuterClass.Java

public class OuterClass {
     private String someVariable = "Non Static";

     private static String anotherStaticVariable = "Static";  

     OuterClass(){

     }

     //Nested classes are static
     static class StaticNestedClass{
        private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable"; 

        //can access private variables declared in the outer class
        public static void getPrivateVariableofOuterClass(){
            System.out.println(anotherStaticVariable);
        }
     }

     //non static
     class InnerClass{

         //can access private variables of outer class
         public String getPrivateNonStaticVariableOfOuterClass(){
             return someVariable;
         }
     }

     public static void accessStaticClass(){
         //can access any variable declared inside the Static Nested Class 
         //even if it private
         String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable; 
         System.out.println(var);
     }

}

OuterClassTest:

public class OuterClassTest {
    public static void main(String[] args) {

        //access the Static Nested Class
        OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();

        //test the private variable declared inside the static nested class
        OuterClass.accessStaticClass();
        /*
         * Inner Class Test
         * */

        //Declaration

        //first instantiate the outer class
        OuterClass outerClass = new OuterClass();

        //then instantiate the inner class
        OuterClass.InnerClass innerClassExample =  outerClass. new InnerClass();

        //test the non static private variable
        System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass()); 

    }

}
3
Pritam Banerjee

Un diagramme

enter image description here

Différence entre static nested et non-static nested classes

  • Les classes imbriquées statiques n'ont pas directement accès aux autres membres (variables et méthodes non statiques) de la classe englobante car, étant donné qu'elle est statique, elle doit accéder aux membres non statiques de sa classe englobante via un objet. Autrement dit, il ne peut pas faire directement référence à des membres non statiques de sa classe englobante. En raison de cette restriction, les classes imbriquées statiques sont rarement utilisées.
  • Les classes imbriquées non statiques (classes internes) ont accès à tous les membres (variables et méthodes statiques et non statiques, y compris private) de sa classe externe et peuvent s'y référer directement de la même manière que les autres membres non statiques de la classe externe. classe faire.

Lire la suite ici

1
yoAlex5

Je pense qu'aucune des réponses ci-dessus ne vous donne le véritable exemple de la différence entre une classe imbriquée et une classe imbriquée statique en termes de conception d'application. Et la principale différence entre la classe imbriquée statique et la classe interne est la possibilité d'accéder au champ d'instance de classe externe.

Jetons un coup d'oeil aux deux exemples suivants.

Classe de nid statique: un modèle de générateur ( https://dzone.com/articles/design-patterns-the-builder-pattern ) est un bon exemple d'utilisation de classes imbriquées statiques.

Pour BankAccount, nous utilisons une classe imbriquée statique, principalement parce que

  1. Une instance de classe de nid statique pourrait être créée avant la classe externe.

  2. Dans le modèle de générateur, le générateur est une classe d'assistance utilisée pour créer le BankAccount.

  3. BankAccount.Builder est uniquement associé à BankAccount. Aucune autre classe n'est liée à BankAccount.Builder. il est donc préférable de les organiser ensemble sans utiliser la convention de nom.
public class BankAccount {

    private long accountNumber;
    private String owner;
    ...

    public static class Builder {

    private long accountNumber;
    private String owner;
    ...

    static public Builder(long accountNumber) {
        this.accountNumber = accountNumber;
    }

    public Builder withOwner(String owner){
        this.owner = owner;
        return this; 
    }

    ...
    public BankAccount build(){
            BankAccount account = new BankAccount(); 
            account.accountNumber = this.accountNumber;
            account.owner = this.owner;
            ...
            return account;
        }
    }
}

Classe interne: Une utilisation courante des classes internes consiste à définir un gestionnaire d'événements. https://docs.Oracle.com/javase/tutorial/uiswing/events/generalrules.html

Pour MyClass, nous utilisons la classe interne, principalement pour les raisons suivantes:

  1. La classe interne MyAdapter doit accéder au membre de la classe externe.

  2. Dans l'exemple, MyAdapter est uniquement associé à MyClass. Aucune autre classe n'est liée à MyAdapter. il est donc préférable de les organiser ensemble sans utiliser de convention de nom

public class MyClass extends Applet {
    ...
        someObject.addMouseListener(new MyAdapter());
    ...
    class MyAdapter extends MouseAdapter {
        public void mouseClicked(MouseEvent e) {
            ...// Event listener implementation goes here...
            ...// change some outer class instance property depend on the event
        }
    }
}
1
Leogao

Le langage de programmation Java vous permet de définir une classe dans une autre classe. Une telle classe s'appelle une classe imbriquée et est illustrée ici:

class OuterClass {
...
class NestedClass {
    ...
    }
}

Les classes imbriquées sont divisées en deux catégories: statique et non statique. Les classes imbriquées déclarées statiques sont appelées classes imbriquées statiques. Les classes imbriquées non statiques sont appelées classes internes ..__ Une chose à ne pas oublier est que 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 accès aux autres membres de la classe englobante que si elles sont statiques. Il ne peut pas accéder aux membres non statiques de la classe externe . Comme les méthodes et les variables de classe, une classe imbriquée statique est associée à sa classe externe. Par exemple, pour créer un objet pour la classe imbriquée statique, utilisez la syntaxe suivante:

OuterClass.StaticNestedClass nestedObject =
 new OuterClass.StaticNestedClass(); 

Pour instancier une classe interne, vous devez d'abord instancier la classe externe. Ensuite, créez l'objet interne dans l'objet externe avec cette syntaxe:

OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();

Pourquoi utilisons-nous des classes imbriquées?

  1. C'est une façon de regrouper logiquement des classes qui ne sont utilisées qu'à un seul endroit.
  2. Cela augmente l'encapsulation.
  3. Cela peut conduire à un code plus lisible et maintenable.

Source: Les tutoriels Java ™ - Classes imbriquées

0
Mithun Debnath

Tout d’abord, il n’existe pas de classe appelée classe statique. Le modificateur statique utilisé avec classe intérieure (appelée classe imbriquée) indique qu’il s’agit d’un membre statique de la classe extérieure, ce qui signifie que nous pouvons y accéder comme avec d’autres instance de la classe Outer. (Quel est l'avantage de statique à l'origine.) 

La différence entre l’utilisation de la classe imbriquée et de la classe interne régulière est la suivante:

OuterClass.InnerClass inner = new OuterClass().new InnerClass();

Nous pouvons d’abord instancier Outerclass puis accéder à Inner.

Mais si Class est imbriqué, la syntaxe est la suivante:

OuterClass.InnerClass inner = new OuterClass.InnerClass();

Qui utilise la syntaxe statique comme implémentation normale du mot clé statique.

0
Sohi