N'est pas une classe englobante Java

366

J'essaie de créer un jeu Tetris et j'obtiens l'erreur du compilateur

Shape is not an enclosing class

quand j'essaye de créer un objet

public class Test {
    public static void main(String[] args) {
        Shape s = new Shapes.ZShape();
    }
}

J'utilise des classes internes pour chaque forme. Voici une partie de mon code

public class Shapes {
    class AShape {
    }
    class ZShape {
    }
}

Qu'est-ce que je fais mal ?

V Sebi
la source
160
new Shape().new ZShape();. La classe a ZShapebesoin d'une instance englobante pour être instanciée.
Sotirios Delimanolis
4
déplacer la classe interne dans un fichier séparé
Dimmduh
Le commentaire @Dimmduh devrait être la réponse dans ce cas. Ils ne devraient pas être des classes internes. Les déplacer identifierait les autres problèmes avec la classe Shape qui existent.
Jeremiah Adams
Pas pour répondre à la question ici mais puis-je suggérer d'utiliser l' héritage ici où AShapeet ZShapeétendre la classe de base Shapes. L'imbrication des classes n'est pas une très bonne conception pour ce problème.
Paramvir Singh Karwal

Réponses:

492

ZShape n'est pas statique, il nécessite donc une instance de la classe externe.

La solution la plus simple consiste à créer ZShape et toute classe imbriquée staticsi vous le pouvez.

Je ferais aussi des champs finalou static finalque vous pouvez aussi.

Peter Lawrey
la source
13
Faire ZShape staticdéfait totalement le but de ce qu'il essaie de faire, qui est d'instancier une copie de ZShape.
Cardano
17
@Cardano le staticrend plus facile, pas plus difficile.
Peter Lawrey
12
une autre solution simple est de faire la classe de fermeture instancier la classe interne, à savoir se ZShape ainsi: ZShape myShape = new Shape().instantiateZShape();. Cela implique que la forme Z que vous obtenez n'existe pas sans forme, ce qui est l'intention ici.
Vince
@Peter Lawrey Comment avez-vous réalisé que toutes les instances de Shape doivent utiliser la même ZShape? Je ne l'obtiens pas de sa source.
L'incroyable
2
Il y a 2 cas si nous voulons statique ou une instance. Le rendre statique n'aidera pas toujours.
Yogesh Chuahan
177

Supposons que RetailerProfileModel est votre classe principale et RetailerPaymentModel est une classe interne à l'intérieur. Vous pouvez créer un objet de la classe Inner en dehors de la classe comme suit:

RetailerProfileModel.RetailerPaymentModel paymentModel
        = new RetailerProfileModel().new RetailerPaymentModel();
Vishal Kumar
la source
34
Cette réponse était vraiment utile, je ne savais pas que vous pouviez appeler nouveau deux fois de suite (et je fais de la java depuis plus de 8 ans!)
PaulBGD
1
Vous pouvez sûrement appeler un nouvel opérateur autant de fois que vous ne voulez pas conserver de référence sur cet objet.
Vishal Kumar
1
Si un objet de la classe interne est créé de cette façon, comment accède-t-il aux membres de la classe externe?
Xingang Huang
1
Au sein de la classe interne elle-même, vous pouvez utiliser OuterClass.this.I je ne pense pas qu'il existe un moyen d'obtenir l'instance en dehors du code de la classe interne. Bien sûr, vous pouvez toujours introduire votre propre propriété: public OuterClass getOuter () {return OuterClass.this; }
Vishal Kumar
Fonctionne pour les tests:underTest = Mockito.mock(Outer.class).new InnerNonStaticClass();
felvhage
48

Ce que je suggérerais n'est pas de convertir la classe non statique en une classe statique car dans ce cas, votre classe interne ne peut pas accéder aux membres non statiques de la classe externe.

Exemple :

class Outer
{
    class Inner
    {
        //...
    }
}

Donc, dans ce cas, vous pouvez faire quelque chose comme:

Outer o = new Outer();
Outer.Inner obj = o.new Inner();
Amit Upadhyay
la source
Qu'en est-il d'Outer.Inner obj = (new Outer) .new Inner ();
Hussain KMR Behestee
1
@HussainKMRBehestee, non, cela ne fonctionnerait pas avec certitude. Cependant, cela fonctionneraitOuter.Inner obj = new Outer().new Inner();
Amit Upadhyay
Mais Amit, ça marche pour moi. Je serais heureux si vous pouviez expliquer pourquoi cela ne devrait pas fonctionner.
Hussain KMR Behestee
1
@HussainKMRBehestee, explication: je peux seulement deviner que la grammaire en Java dit que pour instancier une classe, nous devons appeler le constructeur, et tout en appelant le constructeur ()est obligatoire. Cependant, C, C ++ ce n'est pas un must. Voici un exemple qui ne fonctionne pas. De plus, j'ai trouvé ce post . qui explique plus sur la grammaire en Java et comment ils sont analysés. J'aimerais voir un exemple de cas où cette syntaxe fonctionnera pour vous.
Amit Upadhyay
1
Oh, mon mauvais, c'était une faute de frappe, Outer.Inner obj = (new Outer ()). New Inner (); j'espère que cette fois c'est ok et merci de l'avoir remarqué.
Hussain KMR Behestee
18

Comme indiqué dans les documents :

OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Brennan Miller
la source
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien de référence. Les réponses de lien uniquement peuvent devenir invalides si la page liée change. - De l'avis
Muhammad Omer Aslam
Merci! Juste de commencer.
Brennan Miller
10

Parfois, nous devons créer une nouvelle instance d'une classe interne qui ne peut pas être statique car elle dépend de certaines variables globales de la classe parente. Dans cette situation, si vous essayez de créer l'instance d'une classe interne qui n'est pas statique, une not an enclosing classerreur est levée.

En prenant l'exemple de la question, que faire si elle ZShapene peut pas être statique car elle a besoin d'une variable globale de Shapeclasse?

Comment pouvez-vous créer une nouvelle instance de ZShape? C'est ainsi:

Ajoutez un getter dans la classe parent:

public ZShape getNewZShape() {
    return new ZShape();
}

Accédez-y comme ceci:

Shape ss = new Shape();
ZShape s = ss.getNewZShape();
M9J_cfALt
la source
6
Shape shape = new Shape();
Shape.ZShape zshape = shape.new ZShape();
Антон Лялин
la source
1

J'ai rencontré le même problème. J'ai résolu en créant une instance pour chaque classe publique interne. Quant à votre situation, je vous suggère d'utiliser un héritage autre que les classes internes.

public class Shape {

    private String shape;

    public ZShape zShpae;
    public SShape sShape;

    public Shape(){
      int[][] coords =  noShapeCoords;
      shape = "NoShape";
      zShape = new ZShape();
      sShape = new SShape();
    }

    class ZShape{
      int[][] coords =  zShapeCoords;
      String shape = "ZShape";
    }

    class SShape{
      int[][] coords = sShapeCoords;
      String shape = "SShape";
    }

 //etc
}

alors vous pouvez nouveau Shape (); et visitez ZShape à travers shape.zShape;


la source
1
Une mauvaise solution. Erreur logique. Si la classe interne (par exemple ZShape) nécessite la définition d'un champ, dans le constructeur de la classe externe, vous devez l'obtenir! forme publique (String field1_innerClass, int field2_innerClass ...) {zShape = new ZShape (String field1_innerClass, int field2_innerClass ...) ...}}
Mohsen Abasi
1

Pas besoin de rendre la classe imbriquée statique mais elle doit être publique

public class Test {
    public static void main(String[] args) {
        Shape shape = new Shape();
        Shape s = shape.new Shape.ZShape();
    }
}
Younes
la source
1

Une chose que je n'avais pas réalisé au début en lisant la réponse acceptée était que rendre une classe interne statique est fondamentalement la même chose que la déplacer vers sa propre classe séparée.

Ainsi, lors de l'obtention de l'erreur

xxx n'est pas une classe englobante

Vous pouvez le résoudre de l'une des manières suivantes:

  • Ajoutez le staticmot clé à la classe interne, ou
  • Déplacez-le dans sa propre classe distincte.
Suragch
la source
1

Dans le cas où la classe Parent est singleton, utilisez la méthode suivante:

Parent.Child childObject = (Parent.getInstance()).new Child();

getInstance()renverra l'objet singleton de la classe parent.

Code
la source
0

Pour atteindre l'exigence de la question, nous pouvons mettre les classes en interface:

public interface Shapes {
    class AShape{
    }
    class ZShape{
    }
}

puis utiliser comme auteur essayé auparavant:

public class Test {
    public static void main(String[] args) {
        Shape s = new Shapes.ZShape();
    }
}

Si nous recherchons la solution "logique" appropriée, il faut utiliser le fabricmodèle de conception

Reishin
la source