Не является включающим классом Java

366

Я пытаюсь сделать игру Tetris, и я получаю ошибку компилятора

Shape is not an enclosing class

когда я пытаюсь создать объект

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

Я использую внутренние классы для каждой фигуры. Вот часть моего кода

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

Что я делаю неправильно ?

В Себи
источник
160
new Shape().new ZShape();, Класс ZShapeнуждается в включающем экземпляре для создания экземпляра.
Сотириос Делиманолис
4
переместить внутренний класс в отдельный файл
Dimmduh
@Dimmduh комментарий должен быть ответом в этом случае. Они не должны быть внутренними классами. Перемещение их выявит другие проблемы с существующим классом Shape.
Иеремия Адамс,
Не отвечать на вопрос здесь, но могу ли я предложить здесь использовать наследованиеAShape и ZShapeрасширить базовый класс Shapes. Вложение классов не очень хороший дизайн для этой проблемы.
Парамвир Сингх Карвал

Ответы:

492

ZShape не является статическим, поэтому он требует экземпляра внешнего класса.

Самое простое решение - создать ZShape и любой вложенный класс, staticесли вы можете.

Я также сделал бы любые поля finalили static finalчто вы можете также.

Питер Лори
источник
13
Создание ZShape staticполностью побеждает цель того, что он пытается сделать, который является экземпляром копии ZShape.
Кардано
17
@Cardano staticделает это проще, а не сложнее.
Питер Лори
12
еще одно простого решения , чтобы сделать вмещающий класс Instantiate внутреннего класса, то есть получать ZShape таким образом: ZShape myShape = new Shape().instantiateZShape();. Это подразумевает, что ZShape, который вы получаете, не существует без Shape, что является намерением здесь.
Винс
@Peter Lawrey Как вы поняли, что все экземпляры Shape должны использовать один и тот же ZShape? Я не получаю это из его источника.
Невероятный Янв
2
Есть 2 случая, если мы хотим статический или экземпляр. Создание статики не всегда поможет.
Йогеш Чуахан
177

Предположим, что RetailerProfileModel - это ваш главный класс, а RetailerPaymentModel - это внутренний класс внутри него. Вы можете создать объект класса Inner вне класса следующим образом:

RetailerProfileModel.RetailerPaymentModel paymentModel
        = new RetailerProfileModel().new RetailerPaymentModel();
Вишал Кумар
источник
34
Этот ответ был действительно полезен, я никогда не знал, что вы могли бы звонить новым дважды подряд (и я занимался java в течение 8+ лет!)
PaulBGD
1
Вы, безусловно, можете вызывать новый оператор любое количество раз, пока не захотите сохранять ссылку на этот объект.
Вишал Кумар
1
Если объект внутреннего класса создается таким образом, как он получает доступ к членам внешнего класса?
Синхан Хуан,
1
Внутри самого внутреннего класса вы можете использовать OuterClass.this. Я не думаю, что есть способ получить экземпляр извне кода внутреннего класса. Конечно, вы всегда можете представить свое собственное свойство: public OuterClass getOuter () {return OuterClass.this; }
Вишал Кумар
Работает на тестах:underTest = Mockito.mock(Outer.class).new InnerNonStaticClass();
фельвхаге
48

Я хотел бы предложить не преобразовывать нестатический класс в статический класс, потому что в этом случае ваш внутренний класс не может получить доступ к нестатическим членам внешнего класса.

Пример :

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

Итак, в таком случае вы можете сделать что-то вроде:

Outer o = new Outer();
Outer.Inner obj = o.new Inner();
Амит Упадхяй
источник
Как насчет Outer.Inner obj = (новый Outer) .new Inner ();
Хуссейн KMR Behestee
1
@HussainKMRBehestee, нет, это точно не сработает. Тем не менее, это будет работатьOuter.Inner obj = new Outer().new Inner();
Amit Upadhyay
Но Амит, это работает для меня. Я был бы рад, если бы вы могли объяснить, почему это не должно работать.
Хуссейн KMR Behestee
1
@HussainKMRBehestee, объяснение: я могу только догадываться, что грамматика в Java говорит, что для создания экземпляра класса нам нужно вызвать конструктор, а при вызове конструктора ()обязательно. Тем не менее, C, C ++ это не обязательно. Вот пример, который не работает. Более того, я нашел этот пост . который объясняет больше о грамматике в Java и как они анализируются. Я хотел бы увидеть пример, когда этот синтаксис работает для вас.
Амит
1
О, боже мой, это была опечатка, Outer.Inner obj = (new Outer ()). New Inner (); надеюсь, на этот раз все в порядке, и спасибо, что заметили это.
Хуссейн KMR Behestee
18

Как указано в документации :

OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Бреннан Миллер
источник
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными в случае изменения связанной страницы. - Из обзора
Мухаммед Омер Аслам
Спасибо! Только начал.
Бреннан Миллер
10

Иногда нам нужно создать новый экземпляр внутреннего класса, который не может быть статическим, поскольку он зависит от некоторых глобальных переменных родительского класса. В этой ситуации, если вы попытаетесь создать экземпляр внутреннего класса, который не является статическим, выдается not an enclosing classошибка.

Принимая пример вопроса, что если ZShapeне может быть статическим, потому что ему нужна глобальная переменная Shapeкласса?

Как вы можете создать новый экземпляр ZShape? Вот как:

Добавьте геттер в родительский класс:

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

Доступ к нему так:

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

Я столкнулся с той же проблемой. Я решил, создав экземпляр для каждого внутреннего публичного класса. Что касается вашей ситуации, я предлагаю вам использовать наследование, отличное от внутренних классов.

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
}

тогда вы можете новый Shape (); и посетите ZShape через shape.zShape;


источник
1
Неправильное решение Логическая ошибка Если для внутреннего класса (например, ZShape) требуется установить какое-либо поле, в конструкторе внешнего класса вы должны его получить! public Shape (String field1_innerClass, int field2_innerClass ...) {zShape = new ZShape (String field1_innerClass, int field2_innerClass ...) ...}}
Мохсен Абаси
1

Не нужно делать вложенный класс статическим, но он должен быть публичным

public class Test {
    public static void main(String[] args) {
        Shape shape = new Shape();
        Shape s = shape.new Shape.ZShape();
    }
}
Юнес
источник
1

При чтении принятого ответа я сначала не осознал, что сделать статический внутренний класс - это то же самое, что переместить его в отдельный класс.

Таким образом, при получении ошибки

ххх не является включающим классом

Вы можете решить это одним из следующих способов:

  • Добавьте staticключевое слово во внутренний класс или
  • Переместите его в отдельный класс.
Suragch
источник
1

Если родительский класс одноэлементный, используйте следующий способ:

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

где getInstance()будет возвращать синглтон-объект родительского класса.

Код
источник
0

Чтобы выполнить требование из вопроса, мы можем поместить классы в интерфейс:

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

а затем использовать как автор пытался раньше:

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

Если мы ищем правильное «логическое» решение, следует использовать fabricшаблон проектирования

Reishin
источник