Не є класом 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. Класи вкладання - це не дуже хороший дизайн для цієї проблеми.
— Paramvir Singh Karwal

Відповіді:


492

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

Найпростіше рішення - зробити ZShape і будь-який вкладений клас, staticякщо можете.

Я б також зробив будь-які поля finalчи static finalщо ви також можете.


13
Створення ZShape staticцілком перемагає мету того, що він намагається зробити, а це - копія копії ZShape.
— Cardano

17
@Cardano staticробить це легше, а не важче.
— Пітер Лоурі

12
ще одне простого рішення , щоб зробити вміщає клас Instantiate внутрішнього класу, тобто отримувати ZShape таким чином: ZShape myShape = new Shape().instantiateZShape();. Це означає, що отриманий ZShape не існує без форми, що є тут наміром.
— Вінс

@ Peter Lawrey Як ти зрозумів, що всі екземпляри Shape повинні використовувати один і той же ZShape? Я не отримую цього від його джерела.
— Неймовірний січень

2
Є 2 випадки, якщо ми хочемо статичний або екземпляр. Зробити його статичним не завжди допоможе.
— Йогеш Чуахан

177

Припустимо, RetailerProfileModel - ваш основний клас, а RetailerPaymentModel - це внутрішній клас всередині нього. Ви можете створити об'єкт класу Внутрішній поза класом наступним чином:

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 = (новий Зовнішній) .new Inner ();
— Hussain KMR Behestee

1
@HussainKMRBehestee, ні, це не працювало б точно. Однак це спрацювало бOuter.Inner obj = new Outer().new Inner();
— Аміт Упадгай

Але Аміт, це працює на мене. Я був би радий, якщо ви можете пояснити, чому це не повинно працювати.
— Хусейн KMR Behestee

1
@HussainKMRBehestee, пояснення: Я можу лише здогадуватися, що граматика на Java говорить про те, що для інстанціювання класу нам потрібно викликати конструктор, а при виклику конструктора ()обов'язковий. Однак C, C ++ це не обов'язково. Ось приклад, який не працює. Більше того, я знайшов цю посаду . що пояснює більше про граматику на Java та те, як вони розбираються. Я хотів би побачити зразок випадку, коли цей синтаксис працює для вас.
— Аміт Упадхей

1
О, моє погано, це був помилковий помилок, Outer.Inner obj = (new Outer ()). New Inner (); сподіваюся, що цього разу це нормально і дякую, що помітили це.
— Hussain 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();


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 ...) ...}}
— Mohsen Abasi

1

Не потрібно робити вкладений клас статичним, але він повинен бути відкритим

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

1

Одне, що я спочатку не зрозумів, читаючи прийняту відповідь, - це те, що стати внутрішнім класом статичним - це в основному те саме, що перемістити його в свій окремий клас.

Таким чином, при отриманні помилки

xxx не є класом, що охоплює

Вирішити це можна будь-яким із наступних способів:

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

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модель дизайну

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.