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 ?


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.


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();

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();

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();

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();


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;


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();
    }
}

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.

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.


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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.