Não é uma classe anexa Java

366

Estou tentando criar um jogo Tetris e estou recebendo o erro do compilador

Shape is not an enclosing class

quando tento criar um objeto

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

Estou usando classes internas para cada forma. Aqui está parte do meu código

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

O que estou fazendo errado ?

V Sebi
fonte
160
new Shape().new ZShape();. A classe ZShapeprecisa de uma instância envolvente para ser instanciada.
Sotirios Delimanolis 27/11
4
mover classe interna para arquivo separado
Dimmduh
O comentário @Dimmduh deve ser a resposta neste caso. Eles não devem ser classes internas. Movê-los identificaria os outros problemas com a classe Shape que existem.
Jeremias Adams
Não para responder à pergunta aqui, mas posso sugerir usar herança aqui, onde AShapee ZShapeestender a classe base Shapes. Aninhar classes não é um design muito bom para esse problema.
Paramvir Singh Karwal

Respostas:

492

ZShape não é estático, portanto, requer uma instância da classe externa.

A solução mais simples é criar o ZShape e qualquer classe aninhada, staticse possível.

Eu também faria quaisquer campos finalou static finalque você possa também.

Peter Lawrey
fonte
13
Tornar ZShape statictotalmente derrota o propósito do que ele está tentando fazer, que é instanciar uma cópia ZShape.
Cardano
17
A @Cardano statictorna isso mais fácil, não mais difícil.
Peter Lawrey
12
outra solução simples é fazer com que a classe instanciar encerrando a classe interna, ou seja, recebendo ZShape desta forma: ZShape myShape = new Shape().instantiateZShape();. Isso implica que o ZShape que você obtém não existe sem um Shape, que é a intenção aqui.
Vince
@ Peter Lawrey Como você percebeu que todas as instâncias do Shape precisam usar o mesmo ZShape? Eu não entendo da fonte dele.
O incrível Jan
2
Existem 2 casos, se queremos estática ou uma instância. Tornar estático não ajudará sempre.
Yogesh Chuahan
177

Suponha que RetailerProfileModel seja sua classe Principal e RetailerPaymentModel seja uma classe interna. Você pode criar um objeto da classe Inner fora da classe da seguinte maneira:

RetailerProfileModel.RetailerPaymentModel paymentModel
        = new RetailerProfileModel().new RetailerPaymentModel();
Vishal Kumar
fonte
34
Essa resposta foi realmente útil, eu nunca soube que você poderia chamar de novo duas vezes seguidas (e eu fiz java para 8 + anos!)
PaulBGD
11
Você certamente pode chamar um novo operador várias vezes até não desejar manter uma referência a esse objeto.
Vishal Kumar
11
Se um objeto da classe interna é criado dessa maneira, como ele acessa os membros da classe externa?
Xingang Huang 22/09
11
Dentro da própria classe interna, você pode usar OuterClass.this. Porém, não acho que exista uma maneira de obter a instância de fora do código da classe interna. Obviamente, você sempre pode apresentar sua própria propriedade: public OuterClass getOuter () {return OuterClass.this; }
Vishal Kumar
Trabalhos para testes:underTest = Mockito.mock(Outer.class).new InnerNonStaticClass();
felvhage
48

O que eu sugeriria não é converter a classe não estática em uma classe estática porque, nesse caso, sua classe interna não pode acessar os membros não estáticos da classe externa.

Exemplo:

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

Portanto, nesse caso, você pode fazer algo como:

Outer o = new Outer();
Outer.Inner obj = o.new Inner();
Amit Upadhyay
fonte
E quanto a Outer.Inner obj = (novo Outer) .new Inner ();
Hussain KMR Behestee
11
@HussainKMRBehestee, não, isso não funcionaria com certeza. No entanto, isso iria funcionarOuter.Inner obj = new Outer().new Inner();
Amit Upadhyay
Mas Amit, funciona para mim. Ficaria feliz se você pudesse explicar por que não deve funcionar.
Hussain KMR Behestee
11
@HussainKMRBehestee, explicação: Só posso adivinhar que a gramática em Java diz que, para instanciar uma classe, precisamos chamar o construtor, e ao mesmo tempo em que chama o construtor ()é obrigatório. No entanto, C, C ++ não é obrigatório. Aqui está um exemplo que não funciona. Além disso, eu encontrei este post . que explica mais sobre gramática em Java e como elas são analisadas. Eu adoraria ver um exemplo de caso quando essa sintaxe estiver funcionando para você.
Amit Upadhyay
11
Ah, que pena, foi um erro de digitação, Outer.Inner obj = (new Outer ()). New Inner (); Espero que desta vez esteja tudo bem e obrigado por perceber isso.
Hussain KMR Behestee
18

Conforme declarado nos documentos :

OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Brennan Miller
fonte
Embora esse link possa responder à pergunta, é melhor incluir aqui as partes essenciais da resposta e fornecer o link para referência. As respostas somente para links podem se tornar inválidas se a página vinculada for alterada. - Da avaliação
Muhammad Omer Aslam
Obrigado! Apenas começando.
Brennan Miller
10

Às vezes, precisamos criar uma nova instância de uma classe interna que não possa ser estática, pois depende de algumas variáveis ​​globais da classe pai. Nessa situação, se você tentar criar a instância de uma classe interna que não é estática, not an enclosing classserá gerado um erro.

Tomando o exemplo da pergunta, e se ZShapenão puder ser estático, porque precisa de variável global de Shapeclasse?

Como você pode criar uma nova instância de ZShape? É assim:

Adicione um getter na classe pai:

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

Acesse-o assim:

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

Eu encontrei o mesmo problema. Eu resolvi criando uma instância para cada classe pública interna. quanto à sua situação, sugiro que você use outra herança além das classes 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
}

então você pode novo Shape (); e visite o ZShape através de shape.zShape;


fonte
11
Uma solução errada. Erro lógico. Se a classe interna (por exemplo, ZShape) exigir que qualquer campo seja definido, você deve obtê-lo no construtor da classe externa! public Shape (String field1_innerClass, int field2_innerClass ...) {zShape = new ZShape (String field1_innerClass, int field2_innerClass ...) ...}}
Mohsen Abasi
1

Não há necessidade de tornar a classe aninhada como estática, mas deve ser pública

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

Uma coisa que eu não percebi a princípio ao ler a resposta aceita foi que tornar estática uma classe interna é basicamente a mesma coisa que movê-la para sua própria classe separada.

Assim, ao obter o erro

xxx não é uma classe anexa

Você pode resolvê-lo de uma das seguintes maneiras:

  • Adicione a staticpalavra-chave à classe interna ou
  • Mova-o para sua própria classe separada.
Suragch
fonte
1

Caso a classe Parent seja única, use a seguinte maneira:

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

onde getInstance()retornará o objeto singleton da classe pai.

Código
fonte
0

Para atingir o requisito da pergunta, podemos colocar classes na interface:

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

e use como autor tentado antes:

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

Se estamos procurando a solução "lógica" adequada, deve ser usado o fabricpadrão de design

Reishin
fonte