No es una clase envolvente Java

366

Estoy tratando de hacer un juego de Tetris y obtengo el error del compilador

Shape is not an enclosing class

cuando trato de crear un objeto

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

Estoy usando clases internas para cada forma. Aquí hay parte de mi código

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

Qué estoy haciendo mal ?

V Sebi
fuente
160
new Shape().new ZShape();. La clase ZShapenecesita una instancia de cierre para ser instanciada.
Sotirios Delimanolis
44
mover clase interna a archivo separado
Dimmduh
El comentario de @Dimmduh debería ser la respuesta en este caso. No deberían ser clases internas. Moverlos identificaría los otros problemas con la clase Shape que existen.
Jeremiah Adams
No para responder la pregunta aquí, pero ¿puedo sugerir que use la herencia aquí donde AShapey ZShapeextienda la clase base Shapes. Anidar clases no es un buen diseño para este problema.
Paramvir Singh Karwal

Respuestas:

492

ZShape no es estático, por lo que requiere una instancia de la clase externa.

La solución más simple es hacer ZShape y cualquier clase anidada staticsi puede.

También haría cualquier campo finalo static finalque tú también puedas.

Peter Lawrey
fuente
13
Hacer ZShape statictotalmente derrota el propósito de lo que está tratando de hacer, que es instanciar una copia de ZShape.
Cardano
17
@Cardano lo statichace más fácil, no más difícil.
Peter Lawrey
12
otra solución simple es hacer que el instantiate clase que encierra la clase interna, es decir, conseguir ZShape esta manera: ZShape myShape = new Shape().instantiateZShape();. Implica que el ZShape que obtienes no existe sin una Forma, que es la intención aquí.
Vince
@ Peter Lawrey ¿Cómo te diste cuenta de que todas las instancias de Shape tienen que usar el mismo ZShape? No lo obtengo de su fuente.
El increíble Jan
2
Hay 2 casos si queremos estática o una instancia. Hacerlo estático no siempre ayudará.
Yogesh Chuahan
177

Suponga que RetailerProfileModel es su clase Main y RetailerPaymentModel es una clase interna dentro de ella. Puede crear un objeto de la clase interna fuera de la clase de la siguiente manera:

RetailerProfileModel.RetailerPaymentModel paymentModel
        = new RetailerProfileModel().new RetailerPaymentModel();
Vishal Kumar
fuente
34
Esta respuesta fue realmente útil, nunca supe que podría llamar a la nueva dos veces seguidas (¡y he hecho Java durante más de 8 años!)
PaulBGD
1
Seguramente puede llamar al nuevo operador cualquier número de veces hasta que no desee mantener una referencia de ese objeto.
Vishal Kumar
1
Si un objeto de la clase interna se crea de esta manera, ¿cómo accede a los miembros de la clase externa?
Xingang Huang
1
Dentro de la clase interna en sí, puede usar OuterClass. Esto. No creo que haya una manera de obtener la instancia desde fuera del código de la clase interna. Por supuesto, siempre puede introducir su propia propiedad: public OuterClass getOuter () {return OuterClass.this; }
Vishal Kumar
Funciona para las pruebas:underTest = Mockito.mock(Outer.class).new InnerNonStaticClass();
felvhage
48

Lo que sugeriría es no convertir la clase no estática en una clase estática porque en ese caso, su clase interna no puede acceder a los miembros no estáticos de la clase externa.

Ejemplo:

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

Entonces, en tal caso, puede hacer algo como:

Outer o = new Outer();
Outer.Inner obj = o.new Inner();
Amit Upadhyay
fuente
¿Qué pasa con Outer.Inner obj = (new Outer) .new Inner ();
Hussain KMR Behestee
1
@HussainKMRBehestee, no, eso no funcionaría con seguridad. Sin embargo, esto funcionaríaOuter.Inner obj = new Outer().new Inner();
Amit Upadhyay
Pero Amit, funciona para mí. Me gustaría que me explicaras por qué no debería funcionar.
Hussain KMR Behestee
1
@HussainKMRBehestee, explicación: solo puedo adivinar que la gramática en Java dice que para instanciar una clase necesitamos llamar al constructor, y mientras que llamar al constructor ()es obligatorio. Sin embargo, C, C ++ no es imprescindible. Aquí hay un ejemplo que no funciona. Además, encontré esta publicación . que explica más sobre la gramática en Java y cómo se analizan. Me encantaría ver un caso de muestra cuando esta sintaxis funcione para usted.
Amit Upadhyay
1
Oh, mi mal, fue un error tipográfico, Outer.Inner obj = (new Outer ()). New Inner (); Espero que esta vez esté bien y gracias por notar eso.
Hussain KMR Behestee
18

Como se indica en los documentos :

OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Brennan Miller
fuente
Si bien este enlace puede responder la pregunta, es mejor incluir aquí las partes esenciales de la respuesta y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden volverse inválidas si la página vinculada cambia. - De la opinión
Muhammad Omer Aslam
¡Gracias! Acaba de empezar.
Brennan Miller el
10

A veces, necesitamos crear una nueva instancia de una clase interna que no pueda ser estática porque depende de algunas variables globales de la clase primaria. En esa situación, si intenta crear la instancia de una clase interna que no sea estática, se genera un not an enclosing classerror.

Tomando el ejemplo de la pregunta, ¿qué ZShapepasa si no puede ser estático porque necesita una variable global de Shapeclase?

¿Cómo puedes crear una nueva instancia de ZShape? Así es como:

Agregue un captador en la clase padre:

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

Acceda así:

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

He encontrado el mismo problema. Lo resolví creando una instancia para cada clase pública interna. En cuanto a su situación, le sugiero que use una herencia distinta de las clases internas.

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
}

entonces puedes nueva Forma (); y visite ZShape a través de shape.zShape;


fuente
1
Una solución equivocada. Error lógico Si la clase interna (por ejemplo, ZShape) requiere que se establezca algún campo, ¡en el constructor de la clase externa debe obtenerlo! Forma pública (String field1_innerClass, int field2_innerClass ...) {zShape = new ZShape (String field1_innerClass, int field2_innerClass ...) ...}}
Mohsen Abasi
1

No es necesario que la clase anidada sea estática, pero debe ser pública

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

Una cosa que no me di cuenta al principio al leer la respuesta aceptada fue que hacer que una clase interna sea estática es básicamente lo mismo que moverla a su propia clase separada.

Por lo tanto, al obtener el error

xxx no es una clase de cierre

Puede resolverlo de cualquiera de las siguientes maneras:

  • Agregue la staticpalabra clave a la clase interna, o
  • Muévelo a su propia clase separada.
Suragch
fuente
1

En caso de que la clase Parent sea singleton, use la siguiente manera:

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

donde getInstance()devolverá el objeto singleton de la clase padre.

Código
fuente
0

Para lograr el requisito de la pregunta, podemos poner clases en la interfaz:

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

y luego usar como autor probado antes:

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

Si buscamos la solución "lógica" adecuada, se debe utilizar el fabricpatrón de diseño

Reishin
fuente