Nie jest klasą zamykającą Java


366

Próbuję stworzyć grę Tetris i pojawia się błąd kompilatora

Shape is not an enclosing class

kiedy próbuję stworzyć obiekt

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

Używam klas wewnętrznych dla każdego kształtu. Oto część mojego kodu

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

Co ja robię źle ?


160
new Shape().new ZShape();. Klasa ZShapewymaga wystąpienia instancji obejmującej.
Sotirios Delimanolis

4
przenieś klasę wewnętrzną do oddzielnego pliku
Dimmduh

Komentarz @Dimmduh powinien być odpowiedzią w tym przypadku. Nie powinny być klasami wewnętrznymi. Przeniesienie ich zidentyfikuje inne problemy z istniejącą klasą Shape.
Jeremiah Adams

Nie odpowiadam tutaj na pytanie, ale czy mogę zasugerować użycie dziedziczenia tutaj AShapei ZShaperozszerzenie klasy podstawowej Shapes. Zagnieżdżanie klas nie jest dobrym pomysłem na ten problem.
Paramvir Singh Karwal

Odpowiedzi:


492

ZShape nie jest statyczny, więc wymaga wystąpienia klasy zewnętrznej.

Najprostszym rozwiązaniem jest utworzenie ZShape i dowolnej klasy zagnieżdżonej, staticjeśli możesz.

Chciałbym również dokonywać żadnych pól finallub static finalże można również.


13
Dokonywanie ZShape staticcałkowicie celowość tego, co próbuje robić, co jest kopią instancji ZShape.
Cardano

17
@Cardano staticczyni to łatwiejszym, a nie trudniejszym.
Peter Lawrey

12
Innym prostym rozwiązaniem jest, aby załączając instancję klasy wewnętrzna klasy, czyli coraz ZShape ten sposób: ZShape myShape = new Shape().instantiateZShape();. Oznacza to, że ZShape, który otrzymujesz, nie istnieje bez Kształtu, co jest celem tutaj.
Vince

@Peter Lawrey W jaki sposób zdałeś sobie sprawę, że wszystkie instancje Shape muszą korzystać z tego samego ZShape? Nie rozumiem tego z jego źródła.
Niesamowity

2
Istnieją 2 przypadki, jeśli chcemy statyczny lub instancję. Nadanie statyczności nie zawsze pomoże.
Yogesh Chuahan

177

Załóżmy, że RetailerProfileModel jest Twoją klasą główną, a RetailerPaymentModel to klasa wewnętrzna w tej klasie. Możesz utworzyć obiekt klasy wewnętrznej poza klasą w następujący sposób:

RetailerProfileModel.RetailerPaymentModel paymentModel
        = new RetailerProfileModel().new RetailerPaymentModel();

34
Ta odpowiedź była naprawdę pomocna, nigdy nie wiedziałem, że możesz zadzwonić do nowego dwa razy z rzędu (i robiłem java od
ponad

1
Z pewnością możesz zadzwonić do nowego operatora dowolną liczbę razy, dopóki nie będziesz chciał zachować odwołania do tego obiektu.
Vishal Kumar,

1
Jeśli obiekt klasy wewnętrznej jest tworzony w ten sposób, w jaki sposób uzyskuje on dostęp do członków klasy zewnętrznej?
Xingang Huang,

1
W obrębie samej klasy wewnętrznej możesz użyć OuterClass.this.Nie sądzę jednak, że istnieje sposób, aby uzyskać instancję spoza kodu klasy wewnętrznej. Oczywiście zawsze możesz wprowadzić swoją własność: public OuterClass getOuter () {return OuterClass.this; }
Vishal Kumar,

Działa na testy:underTest = Mockito.mock(Outer.class).new InnerNonStaticClass();
felvhage

48

Sugerowałbym, aby nie konwertować klasy niestatycznej na klasę statyczną, ponieważ w takim przypadku klasa wewnętrzna nie może uzyskać dostępu do elementów niestatycznych klasy zewnętrznej.

Przykład:

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

W takim przypadku możesz zrobić coś takiego:

Outer o = new Outer();
Outer.Inner obj = o.new Inner();

Co z Outer.Inner obj = (new Outer) .new Inner ();
Hussain KMR Behestee

1
@HussainKMRBehestee, nie, to na pewno nie zadziała. To jednak zadziałałobyOuter.Inner obj = new Outer().new Inner();
Amit Upadhyay

Ale Amit, to działa dla mnie. Byłbym zadowolony, gdybyś mógł wyjaśnić, dlaczego to nie powinno działać.
Hussain KMR Behestee

1
@HussainKMRBehestee, wyjaśnienie: Mogę tylko zgadywać, że gramatyka w Javie mówi, że aby utworzyć instancję klasy, musimy wywołać konstruktor, a podczas wywoływania konstruktora ()jest obowiązkowy. Jednak C, C ++ nie jest koniecznością. Oto przykład, który nie działa. Ponadto znalazłem ten post . co wyjaśnia więcej na temat gramatyki w Javie i tego, jak są one przetwarzane. Chciałbym zobaczyć przykładowy przypadek, gdy ta składnia działa dla Ciebie.
Amit Upadhyay,

1
O mój Boże, to była literówka, Outer.Inner obj = (new Outer ()). New Inner (); mam nadzieję, że tym razem wszystko jest w porządku i dziękuję za zauważenie tego.
Hussain KMR Behestee

18

Jak stwierdzono w dokumentach :

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

Chociaż ten link może odpowiedzieć na pytanie, lepiej dołączyć tutaj istotne części odpowiedzi i podać link w celach informacyjnych. Odpowiedzi zawierające tylko łącze mogą stać się nieprawidłowe, jeśli połączona strona ulegnie zmianie. - Z recenzji
Muhammad Omer Aslam

Dzięki! Dopiero się zaczyna.
Brennan Miller

10

Czasami musimy utworzyć nową instancję klasy wewnętrznej, która nie może być statyczna, ponieważ zależy od niektórych zmiennych globalnych klasy nadrzędnej. W takiej sytuacji, jeśli spróbujesz utworzyć instancję klasy wewnętrznej, która nie jest statyczna, generowany not an enclosing classjest błąd.

Biorąc przykład pytania, co jeśli ZShapenie może być statyczny, ponieważ potrzebuje globalnej zmiennej Shapeklasy?

Jak utworzyć nową instancję ZShape? Oto jak:

Dodaj moduł pobierający w klasie nadrzędnej:

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

Uzyskaj dostęp w ten sposób:

Shape ss = new Shape();
ZShape s = ss.getNewZShape();


1

Napotkałem ten sam problem. Rozwiązałem, tworząc instancję dla każdej wewnętrznej klasy publicznej. co do twojej sytuacji, sugeruję, abyś używał dziedziczenia innego niż klasy wewnętrzne.

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
}

wtedy możesz nowy Shape (); i odwiedź ZShape poprzez shape.zShape;


1
Niewłaściwe rozwiązanie. Błąd logiczny. Jeśli klasa wewnętrzna (np. ZShape) wymaga ustawienia dowolnego pola, w konstruktorze klasy zewnętrznej musisz je zdobyć! public Shape (String field1_innerClass, int field2_innerClass ...) {zShape = new ZShape (String field1_innerClass, int field2_innerClass ...) ...}}
Mohsen Abasi

1

Nie trzeba ustawiać zagnieżdżonej klasy jako statyczną, ale musi ona być publiczna

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

1

Jedną z rzeczy, których na początku nie zdawałem sobie sprawy, gdy czytałem zaakceptowaną odpowiedź, było to, że utworzenie statycznej klasy wewnętrznej jest w zasadzie tym samym, co przeniesienie jej do osobnej klasy.

Tak więc, gdy pojawia się błąd

xxx nie jest klasą zamykającą

Możesz go rozwiązać na jeden z następujących sposobów:

  • Dodaj staticsłowo kluczowe do klasy wewnętrznej lub
  • Przenieś go do osobnej klasy.

1

W przypadku, gdy klasa Parent jest singletona, użyj następującego sposobu:

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

gdzie getInstance()zwróci obiekt singletonu klasy nadrzędnej.


0

Aby spełnić wymaganie zawarte w pytaniu, możemy umieścić klasy w interfejsie:

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

a następnie użyj jako autor próbował wcześniej:

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

Jeśli szukamy właściwego „logicznego” rozwiązania, należy zastosować fabricwzorzec projektowy

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.