Quelle est la principale différence entre une classe interne et une classe imbriquée statique en Java? La conception / mise en œuvre joue-t-elle un rôle dans le choix de l'une d'entre elles?
Quelle est la principale différence entre une classe interne et une classe imbriquée statique en Java? La conception / mise en œuvre joue-t-elle un rôle dans le choix de l'une d'entre elles?
Réponses:
Depuis le tutoriel Java :
Les classes imbriquées sont divisées en deux catégories: statiques et non statiques. 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 à l'aide du nom de classe qui les entoure:
OuterClass.StaticNestedClass
Par exemple, pour créer un objet pour la classe imbriquée statique, utilisez cette syntaxe:
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 de InnerClass ne peut exister que dans une instance de OuterClass et a 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 outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
voir: Tutoriel Java - Classes imbriquées
Pour être complet, notez qu'il existe également une classe interne sans instance englobante :
class A {
int t() { return 1; }
static A a = new A() { int t() { return 2; } };
}
Ici, new A() { ... }
est une classe interne définie dans un contexte statique et n'a pas d'instance englobante.
import OuterClass.StaticNestedClass;
puis référencer la classe tout comme OuterClass.
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
?
Le tutoriel Java dit :
Terminologie: les classes imbriquées sont divisées en deux catégories: statiques et non statiques. 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.
Dans le langage courant, les termes "imbriqué" et "intérieur" sont utilisés de manière interchangeable par la plupart des programmeurs, mais j'utiliserai le terme correct "classe imbriquée" qui couvre à la fois intérieur 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. Cependant, plus d'un niveau d'imbrication de classe est rare, car il s'agit généralement d'une mauvaise conception.
Il existe trois raisons pour lesquelles vous pouvez créer une classe imbriquée:
Il existe quatre types de classes imbriquées en Java . En bref, ce sont:
Permettez-moi de développer plus en détail.
Les classes statiques sont les plus faciles à comprendre car elles n'ont rien à voir avec les instances de la classe conteneur.
Une classe statique est une classe déclarée comme membre statique d'une autre classe. Tout comme les autres membres statiques, une telle classe n'est en fait qu'un cintre qui utilise la classe conteneur comme espace de noms, par exemple la classe Goat déclarée comme membre statique de la classe Rhino dans le paquet pizza est connue sous le nom de pizza.Rhino.Goat .
package pizza;
public class Rhino {
...
public static class Goat {
...
}
}
Franchement, les classes statiques sont une fonctionnalité assez inutile car les classes sont déjà divisées en espaces de noms par des packages. La seule vraie raison concevable pour créer une classe statique est qu'une telle classe a accès aux membres statiques privés de sa classe contenante, mais je trouve que c'est une justification assez boiteuse pour que la fonction de classe statique existe.
Une classe interne est une classe déclarée comme 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 connue comme qualifiée par son nom de classe contenant, pizza.Rhino.Goat , mais à l'intérieur de la classe contenant, elle peut être connue par son nom simple. Cependant, chaque instance d'une classe interne est liée à une instance particulière de sa classe conteneur: ci-dessus, le Goat créé dans jerry , est implicitement lié à l' instance de Rhino this dans jerry . Sinon, nous rendons l' instance Rhino associée explicite lorsque nous instancions Goat :
Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();
(Remarquez que vous faites référence au type interne comme simplement Goat dans la nouvelle syntaxe étrange : Java déduit le type contenant de la partie rhino . Et, oui, new rhino.Goat () aurait été plus logique pour moi aussi.)
Alors qu'est-ce que cela nous apporte? Eh bien, l'instance de classe interne a accès aux membres d'instance de l'instance de classe conteneur. Ces membres d'instance englobants sont référencés à l'intérieur de la classe interne via seulement leurs noms simples, pas via ceci ( ceci dans la classe interne fait référence à l'instance de classe interne, pas l'instance de classe contenant associée):
public class Rhino {
private String barry;
public class Goat {
public void colin() {
System.out.println(barry);
}
}
}
Dans la classe interne, vous pouvez vous référer à cette de la classe contenant comme Rhino.this , et vous pouvez utiliser ce pour se référer à ses membres, par exemple Rhino.this.barry .
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 conteneur, elle ne peut donc être instanciée et accéder à ses membres que dans sa méthode conteneur. Le gain est qu'une instance de classe interne locale est liée à et peut accéder aux variables locales finales de sa méthode conteneur. Lorsque l'instance utilise un local final de sa méthode conteneur, 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 fait de la version brute et limitée de fermetures de Java).
Parce qu'une classe interne locale n'est ni le membre d'une classe ou 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 comme dans 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 conteneur this au moment de la création de l'instance, et ainsi les membres d'instance de la classe conteneur sont accessibles comme dans une instance classe intérieure. Une classe interne locale est instanciée simplement via son nom, par exemple la classe interne locale Cat est instanciée en tant que nouveau Cat () , pas nouveau this.Cat () comme vous pouvez vous y attendre.
Une classe interne anonyme est un moyen syntaxiquement pratique d'écrire une classe interne locale. Le plus souvent, une classe interne locale est instanciée au plus une fois à chaque fois que sa méthode conteneur est exécutée. Ce serait bien, alors, si nous pouvions combiner la définition de la classe interne locale et sa seule instanciation en une seule forme de syntaxe pratique, et ce serait aussi bien si nous n'avions pas à trouver un nom pour la classe (le moins inutile noms que contient votre code, mieux c'est). Une classe interne anonyme permet les deux choses suivantes:
new *ParentClassName*(*constructorArgs*) {*members*}
Il s'agit d'une expression renvoyant une nouvelle instance d'une classe sans nom qui étend ParentClassName . Vous ne pouvez pas fournir votre propre constructeur; au lieu de cela, on est implicitement fourni qui appelle simplement le super constructeur, donc les arguments fournis doivent correspondre au super constructeur. (Si le parent contient plusieurs constructeurs, le plus "simple" est appelé, "le plus simple" tel que déterminé par un ensemble de règles assez complexes qui ne vaut pas la peine d'être étudié en détail - faites juste 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 InterfaceName . Encore une fois, vous ne pouvez pas fournir votre propre constructeur; dans ce cas, Java fournit implicitement un constructeur no-arg, do-nothing (il n'y aura donc jamais d'argument constructeur dans ce cas).
Même si vous ne pouvez pas donner de constructeur à une classe interne anonyme, vous pouvez toujours effectuer la configuration de votre choix à l'aide d'un bloc d'initialisation (un bloc {} placé en dehors de toute méthode).
Soyez clair qu'une classe interne anonyme est tout simplement un moyen moins flexible de créer une classe interne locale avec une seule instance. Si vous voulez une classe interne locale qui implémente plusieurs interfaces ou qui implémente des interfaces tout en étendant une classe autre que Object ou qui spécifie son propre constructeur, vous êtes bloqué en créant une classe interne locale nommée régulière.
Je ne pense pas que la vraie différence soit devenue claire dans les réponses ci-dessus.
D'abord pour obtenir les bons termes:
Jusqu'à présent, la réponse de Martin est juste. Cependant, la vraie question est: quel est le but de déclarer une classe imbriquée statique ou non?
Vous utilisez des 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 bête différente. Semblables aux classes internes anonymes, ces classes imbriquées sont en fait 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 talon 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 souhaitez avoir une référence d'un élément enfant au conteneur parent. À l'aide d'une classe imbriquée non statique, cela fonctionne sans 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 que le compilateur génère pour une classe imbriquée (non statique), cela pourrait 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 voir, le compilateur crée un champ caché 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 la 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 donc 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 qui n'a tout simplement aucun nom qui lui est associé et ne peut pas être référencée plus tard.
Je pense qu'aucune des réponses ci-dessus ne vous explique la vraie différence entre une classe imbriquée et une classe imbriquée statique en termes de conception d'application:
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 doit exister que pour servir sa classe englobante , si une classe imbriquée est utile à d'autres classes (pas seulement l'enveloppe), elle doit être déclarée comme classe de niveau supérieur.
Classe imbriquée non statique : est implicitement associée à l'instance englobante de la classe conteneur , cela signifie qu'il est possible d'appeler des méthodes et d'accéder aux variables 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 à l'instance de classe englobante et invoquer des méthodes dessus, elle doit donc être utilisée lorsque la classe imbriquée n'a pas besoin d'accéder à une instance de la classe englobante. Une utilisation courante de la classe imbriquée statique consiste à implémenter un composant de l'objet externe.
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, contrairement à la statique .
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 à l'intérieur du corps d'une autre classe englobante. Ils sont de deux types - statiques et non statiques.
Ils sont traités comme des membres de la classe englobante, vous pouvez donc 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 public
ou package-private.
Les classes internes alias les classes sans pile ont accès aux autres membres de la classe supérieure, même si elles sont déclarées privées tandis que les classes imbriquées statiques n'ont pas accès aux autres membres de la classe supérieure.
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 principale différence entre eux, vous ne pouvez pas créer une Inner2
instance sans Outer où vous pouvez créer un Inner1
objet 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 Class A
membres et Class B
n'est liée qu'à Class A
. Les classes internes entrent en jeu.
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 une classe interne statique?
Vous définiriez une classe interne statique lorsque vous savez qu'elle n'a aucune relation avec l'instance de la classe / classe supérieure englobante. Si votre classe interne n'utilise pas les méthodes ou les champs de la classe externe, c'est juste une perte d'espace, alors rendez-la statique.
Par exemple, pour créer un objet pour la classe imbriquée statique, utilisez cette syntaxe:
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 conteneur / classe supérieure pour fonctionner. Cela peut vous aider à réduire le nombre d'objets créés par votre application au moment de l'exécution.
OuterClass.Inner2 inner = outer.new Inner2();
?
static inner
est une contradiction en termes.
Voici les principales différences et similitudes entre la classe interne Java et la classe imbriquée statique.
J'espère que cela aide!
Associé à l'instance de la classe englobante , pour l'instancier, il faut d'abord une instance de la classe externe (notez le nouveau mot-clé place):
Outerclass.InnerClass innerObject = outerObject.new Innerclass();
Impossible de définir un membre statique lui-même
Impossible d'accéder aux méthodes ou champs d' instance de classe externe
Pas associé à une instance de classe englobante Donc pour l'instancier:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
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 autre classe, il est logique de l'intégrer dans cette classe et de garder les deux ensemble. L'imbrication de ces "classes d'assistance" rend leur package plus rationalisé.
Cela augmente l'encapsulation: considérez deux classes de niveau supérieur, A et B, où B a besoin d'accéder à des 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 plus facile à gérer: l' imbrication de petites classes dans des classes de niveau supérieur rapproche le code de son utilisation.
Je pense que la convention qui est généralement suivie est la suivante:
Cependant, quelques autres points à retenir sont:
Les classes de niveau supérieur et la classe imbriquée statique sont sémantiquement les mêmes, sauf que dans le cas d'une classe imbriquée statique, elle peut faire référence statique aux champs / méthodes statiques privés de sa classe [parent] externe et vice versa.
Les classes internes ont accès aux variables d'instance de l'instance englobante de la classe Outer [parent]. Cependant, toutes les classes internes n'ont pas d'instances englobantes, par exemple les classes internes dans des contextes statiques, comme une classe anonyme utilisée dans un bloc d'initialisation statique, n'en ont pas.
Par défaut, la classe anonyme étend la classe parent ou implémente l'interface parent et il n'y a pas de clause supplémentaire pour étendre une autre classe ou implémenter d'autres interfaces. Donc,
new YourClass(){};
veux dire class [Anonymous] extends YourClass {}
new YourInterface(){};
veux dire class [Anonymous] implements YourInterface {}
Je pense que la plus grande question qui reste ouverte, laquelle utiliser et quand? Eh bien, cela dépend principalement du scénario auquel vous faites face, mais la lecture de la réponse donnée par @jrudolph peut vous aider à prendre une décision.
Classe imbriquée: classe à l'intérieur de la classe
Les types:
Différence:
Classe imbriquée non statique [classe intérieure]
Dans la classe imbriquée non statique, l'objet de la classe interne existe dans l'objet de la classe externe. Ainsi, ce 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 de l'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 souhaitez accéder à x, écrivez la méthode interne suivante
outerclass.nestedclass.x; i.e. System.out.prinltn( outerclass.nestedclass.x);
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'instance (objet) de la classe externe. Lorsque l'instance de la classe externe sort de la portée, les instances de classe interne cessent également d'exister.
La classe statique imbriquée n'a pas d'instance concrète. Il est juste chargé lors de sa première utilisation (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 de tas / pile, car il n'est pas nécessaire de créer une instance de cette classe. Par conséquent, la règle de base est d'essayer de définir une classe imbriquée statique, avec une portée aussi limitée que possible (privé> = classe> = protégé> = public), puis de le convertir en classe interne (en supprimant l'identifiant "statique") et de desserrer la portée, si c'est vraiment nécessaire.
Il existe une subtilité dans l'utilisation des classes statiques imbriquées qui pourraient être utiles 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 pas être instanciés tant que le constructeur de la classe n'est pas appelé, ou du moins pas après que les attributs sont référencés pour la première fois, même si ils sont marqués comme «définitifs».
Considérez 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 'nested' et 'innerItem' sont tous deux déclarés comme 'final statique'. le paramètre nested.innerItem n'a lieu qu'après l'instanciation de la classe (ou du moins pas après le premier référencement de l'élément statique imbriqué), comme vous pouvez le constater par vous-même en commentant et en décommentant les lignes auxquelles je me réfère, au dessus de. Il n'en va pas de même pour «externalItem».
C'est du moins ce que je vois dans Java 6.0.
Les termes sont utilisés de manière interchangeable. Si vous voulez être vraiment pédant à ce sujet, vous pouvez définir "classe imbriquée" pour faire référence à une classe interne statique, qui n'a pas d'instance englobante. Dans le code, vous pourriez avoir quelque chose comme ceci:
public class Outer {
public class Inner {}
public static class Nested {}
}
Ce n'est pas vraiment une définition largement acceptée.
Dans le cas de la création d'une instance, l'instance de la classe interne non statique est créée avec la référence de l'objet de la classe externe dans laquelle elle est définie. Cela signifie qu'il a une instance fermée. Mais l'instance de classe interne statique est créée avec la référence de la classe externe, et non avec la référence de l'objet de la classe externe. Cela signifie qu'il n'a pas d'instance fermée.
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….
}
}
Je ne pense pas qu'il y ait beaucoup à ajouter ici, la plupart des réponses expliquent parfaitement les différences entre la classe imbriquée statique et les classes internes. Cependant, considérez le problème suivant lorsque vous utilisez des classes imbriquées par rapport aux classes internes. Comme mentionné dans quelques réponses, les classes internes ne peuvent pas être instanciées sans et l'instance de leur classe englobante, ce qui signifie qu'elles détiennent un pointeur vers l'instance de leur classe englobante, ce qui peut entraîner un dépassement de mémoire ou une exception de dépassement de pile en raison du fait que le GC 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 affichera " Je suis détruit! ", Mais ce commentaire ne le sera pas.
La raison en est que l'instance interne blanche est toujours référencée GC ne peut pas la collecter et parce qu'elle référence (a un pointeur vers) l'instance externe, elle n'est pas collectée également. Avoir suffisamment de ces objets dans votre projet et manquer de mémoire.
Comparé aux classes internes statiques qui ne contiennent pas de point sur l'instance de classe interne car elle n'est pas liée à l'instance mais à la classe. Le programme ci-dessus peut imprimer " Je suis détruit! " Si vous rendez la classe intérieure statique et instanciée avecOuter.Inner i = new Outer.Inner();
La classe imbriquée est un terme très général: chaque classe qui n'est pas de niveau supérieur est une classe imbriquée. Une classe interne est une classe imbriquée non statique. Joseph Darcy a écrit une très belle explication sur les classes imbriquées, internes, membres et de niveau supérieur .
Ummm ... une classe interne EST une classe imbriquée ... voulez-vous dire classe anonyme et classe interne?
Edit: Si vous vouliez vraiment dire interne vs anonyme ... une classe interne est juste 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 de manière anonyme, aucune classe "réelle" n'est définie, comme dans:
public class A {
}
A anon = new A() { /* you could change behavior of A here */ };
Modifier davantage:
Wikipédia prétend qu'il y a une différence dans Java, mais je travaille avec Java depuis 8 ans, et c'est la première fois que j'entends une telle distinction ... sans mentionner qu'il n'y a aucune référence pour sauvegarder la revendication ... bas ligne, une classe interne est une classe définie dans une classe (statique ou non), et imbriquée est juste un autre terme pour signifier la même chose.
Il y a une différence subtile entre les classes imbriquées statiques et non statiques ... fondamentalement, les classes internes non statiques ont un accès implicite aux champs d'instance et aux méthodes de la classe englobante (donc elles ne peuvent 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 champs et méthodes d'instance, et PEUVENT être construites dans un contexte statique.
Cibler l'apprenant, novice en Java et / ou en classes imbriquées
Les classes imbriquées peuvent être:
1. Classes imbriquées statiques.
2. Classes imbriquées non statiques. (également connu sous le nom de classes internes ) => S'il vous plaît rappelez-vous ceci
1. classes internes
Exemple:
class OuterClass {
/* some code here...*/
class InnerClass { }
/* some code here...*/
}
Les classes internes sont des sous-ensembles de classes imbriquées:
Spécialité de classe intérieure:
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:
Conclusion:
Question: Quelle est la principale différence entre une classe interne et une classe imbriquée statique en Java?
Réponse: passez simplement en revue les spécificités de chaque classe mentionnée ci-dessus.
La classe interne et la classe statique imbriquée en Java sont toutes deux des classes déclarées dans une autre classe, connue sous le nom de 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 interne.
Qu'est-ce que la classe intérieure en Java?
Toute classe qui n'est pas un niveau supérieur ou déclarée dans une autre classe est connue comme classe imbriquée et parmi ces classes imbriquées, les classes déclarées non statiques sont appelées classe interne en Java. il existe trois types de classe Inner en Java:
1) Classe interne locale - est déclarée à l'intérieur d'un bloc de code ou d'une méthode.
2) Classe interne anonyme - est une classe qui n'a pas de nom à référencer et initialisée au même endroit où elle est créée.
3) Membre classe interne - est déclaré comme 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 qui est déclarée dans une classe comme 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 tout 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 attaché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 aux données statiques des membres de la classe externe, y compris privés.
2) La classe imbriquée statique ne peut pas accéder au membre ou à la méthode de données non statiques (instance) .
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 exemple
Je pense que les gens ici devraient remarquer à Poster que: Static Nest Class uniquement la première classe intérieure. Par exemple:
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ésumez, la classe statique ne dépend pas de la classe qu'elle contient. Donc, ils ne peuvent pas en classe normale. (car la classe normale a besoin d'une instance).
Lorsque nous déclarons une classe membre statique à l'intérieur d'une classe, elle est connue comme 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 à l'intérieur d'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);
}
}
}
Ce qui suit est un exemple de static nested class
etinner 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());
}
}
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'œil aux deux exemples suivants.
Classe d'imbrication statique: un bon exemple d'utilisation de classes imbriquées statiques est le modèle de générateur ( https://dzone.com/articles/design-patterns-the-builder-pattern ).
Pour BankAccount, nous utilisons une classe imbriquée statique, principalement parce que
Une instance de classe d'imbrication statique peut être créée avant la classe externe.
Dans le modèle de générateur, le générateur est une classe d'assistance qui est utilisée pour créer le BankAccount.
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 parce que:
La classe interne MyAdapter doit accéder au membre de classe externe.
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
}
}
}
Tout d'abord, il n'y a pas de classe appelée classe statique.Le modificateur statique utilisé avec la classe interne (appelée classe imbriquée) indique qu'il s'agit d'un membre statique de la classe externe, ce qui signifie que nous pouvons y accéder comme avec d'autres membres statiques et sans en avoir instance de la classe Outer. (Ce qui est à l'origine de l'électricité statique.)
La différence entre l'utilisation de la classe Nested et de la classe Inner standard est:
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
D'abord, nous pouvons instancier Outerclass puis nous pouvons accéder à Inner.
Mais si la classe est imbriquée, la syntaxe est la suivante:
OuterClass.InnerClass inner = new OuterClass.InnerClass();
Qui utilise la syntaxe statique comme implémentation normale du mot-clé statique.
Le langage de programmation Java vous permet de définir une classe dans une autre classe. Une telle classe est appelée une classe imbriquée et est illustrée ici:
class OuterClass {
...
class NestedClass {
...
}
}
Les classes imbriquées sont divisées en deux catégories: statiques et non statiques. 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 que nous devons garder à l'esprit est que les classes imbriquées non statiques (classes internes) ont accès aux autres membres de la classe englobante, même si elles sont déclarées privées. 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 pour les méthodes et 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 cette syntaxe:
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 nous utilisons des classes imbriquées
La différence est qu'une déclaration de classe imbriquée qui est également statique peut être instanciée en dehors de la classe englobante.
Lorsque vous avez une déclaration de classe imbriquée qui n'est pas statique, également connue sous le nom de classe interne , Java ne vous permet pas de l'instancier sauf via la classe englobante. L'objet créé à partir de la classe interne est lié à l'objet créé à partir de la classe externe, afin que la classe interne puisse référencer les champs de la classe externe.
Mais s'il est statique, le lien n'existe pas, les champs externes ne sont pas accessibles (sauf via une référence ordinaire comme tout autre objet) et vous pouvez donc instancier la classe imbriquée par elle-même.
C'est assez simple, en comparant les classes locales statiques et les classes internes non statiques.
Différences:
Classe locale statique:
ne peut accéder qu'aux membres statiques de la classe externe.
Impossible d'avoir des initialiseurs statiques
Impossible d'accéder directement à l'extérieur de la fonction où son déclaré
J'ai illustré divers scénarios corrects et d'erreur possibles qui peuvent se produire dans le code java.
class Outter1 {
String OutStr;
Outter1(String str) {
OutStr = str;
}
public void NonStaticMethod(String st) {
String temp1 = "ashish";
final String tempFinal1 = "ashish";
// below static attribute not permitted
// static String tempStatic1 = "static";
// below static with final attribute not permitted
// static final String tempStatic1 = "ashish";
// synchronized keyword is not permitted below
class localInnerNonStatic1 {
synchronized public void innerMethod(String str11) {
str11 = temp1 +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// static method with final not permitted
public static void innerStaticMethod(String str11) {
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
}
// static class not permitted below
// static class localInnerStatic1 { }
}
public static void StaticMethod(String st) {
String temp1 = "ashish";
final String tempFinal1 = "ashish";
// static attribute not permitted below
//static String tempStatic1 = "static";
// static with final attribute not permitted below
// static final String tempStatic1 = "ashish";
class localInnerNonStatic1 {
public void innerMethod(String str11) {
str11 = temp1 +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// static method with final not permitted
public static void innerStaticMethod(String str11) {
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
}
// static class not permitted below
// static class localInnerStatic1 { }
}
// synchronized keyword is not permitted
static class inner1 {
static String temp1 = "ashish";
String tempNonStatic = "ashish";
// class localInner1 {
public void innerMethod(String str11) {
str11 = temp1 +" sharma";
str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
public static void innerStaticMethod(String str11) {
// error in below step
str11 = temp1 +" india";
//str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
//}
}
//synchronized keyword is not permitted below
class innerNonStatic1 {
//This is important we have to keep final with static modifier in non
// static innerclass below
static final String temp1 = "ashish";
String tempNonStatic = "ashish";
// class localInner1 {
synchronized public void innerMethod(String str11) {
tempNonStatic = tempNonStatic +" ...";
str11 = temp1 +" sharma";
str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// error in below step
public static void innerStaticMethod(String str11) {
// error in below step
// str11 = tempNonStatic +" india";
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
//}
}
}
item 22 : Favor static member classes over non static