Java Inner Class расширяет внешний класс

В Java есть некоторые случаи, когда внутренний класс расширяет внешний класс.

Например, java.awt.geom.Arc2D.Float является внутренним классом java.awt.geom.Arc2D, а также расширяет Arc2D. (c.f. http://download.oracle.com/javase/6/docs/api/java/awt/geom/Arc2D.Float.html)

Кроме того, sun.org.mozilla.javascript.internal.FunctionNode.Jump расширяет sun.org.mozilla.javascript.internal.Node, который является суперклассом FunctionNode. (извините... не могу найти ссылку на javadoc)

Для меня это кажется странным. Не могли бы вы создать их?

new Arc2D.Float.Float() //n.b. I couldn't get this to compile in Intellij IDEA;

new FunctionNode.Jump.Jump.Jump(1); // I could get this to compile

Какая цель заключается в том, чтобы подкласс вложен как внутренний класс суперкласса?

Я задавался вопросом, нужно ли было получить доступ к чему-то в суперклассе, но если вы хотите получить доступ к любым переменным/методам в родительском, вы можете использовать

super.variable;

или

super.method();

Изменить 1: jjnguy предложил ему сохранить логику в одном и том же месте. В этом случае, почему бы вам не написать файл com.mypackage.AbstractTest:

abstract class AbstractTest {
  abstract String getString();
}

class ExtensionTest extends AbstractTest {
  @Override
  String getString() {
    return "hello world";
  }
}

... а не:

abstract class AbstractTest {
  abstract String getString();

  class ExtensionTest extends AbstractTest {
    @Override
    String getString() {
      return "hello world";
    }
  }
}

Изменить 2: Правильно было указано, что предложение в моем предыдущем редактировании было ошибочным, так как не удалось построить ExtensionTest за пределами пакета. Тем не менее, я думал об этом в течение выходных, так что о следующем:

abstract class Test {
  public class ExtensionTest extends AbstractTest {
    @Override
    String getString() {
      return "hello world";
    }
  }

  private abstract class AbstractTest {
    abstract String getString();
  }
} 

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

В моем сознании, кажется, что у плохого дизайна есть класс, который может иметь бесконечное число тех же подклассов, вложенных в него. (Контекст: это произошло, пытаясь создать словарь для утилиты завершения кода, и бросил исключение StackOverflowException. Я нашел обходное решение, но я просто не понимаю, почему он был спроектирован именно так.)

Ответ 1

Посмотрите на Java Point2D. Он имеет два внутренних класса, которые являются его подклассами.

Важно отметить, что они являются static внутренними классами. Это имеет совершенно четкое значение, что регулярный внутренний класс. Точно так же, как статический метод, статический класс определяется на уровне класса, а не на уровне объекта.

В случае Point2D это делается для логической связи классов и их логики. Это помогает пользователю типа abstract Point2D найти реализацию, которую они могут использовать.

В ответ на ваше редактирование я хотел бы отметить один важный факт. Один файл Java может содержать только один открытый класс кроме для общедоступных внутренних классов. Хотя оба ваших примера могут компилироваться, они не разрешают доступ к этим классам для публики. Если вы хотите представить несколько публичных классов кому-то в одном файле, вы должны использовать общедоступные статические внутренние классы.

Ответ 2

Существует два случая внутренних классов:

  • static внутренние классы. Внутренний класс не поддерживает ссылку на внешний класс.

  • нестатические внутренние классы. Внутренний класс сохраняет ссылку на внешний класс.

Случай статического внутреннего класса, который расширяет внешний класс, не так интересен, как нестатический внутренний класс, расширяющий внешний класс.

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

Посмотрим на некоторый код:

Outer a = new Outer();
Outer.Inner b = a.new Inner();

// Only possible when Inner extends Outer:
Outer.Inner c = a.new Inner().new Inner();

Если вы знаете шаблон построителя, его можно использовать для OOP-версии:

public abstract class Command {

    // Not possible to create the command, else than from this file!
    private Command() {
    }

    public abstract void perform();

    public static class StartComputer extends Command {
        public void perform() {
            System.out.println("Starting Computer");
        }
    }

    public class OpenNotepad extends Command {
        public void perform() {
            Command.this.perform();
            System.out.println("Opening Notepad");
        }
    }

    public class ShutdownComputer extends Command {
        public void perform() {
            Command.this.perform();
            System.out.println("Shutting Computer");
        }
    }

}

Используется как: new Command.StartComputer().new OpenNotepad().new ShutdownComputer().perform();.

Ответ 3

Там 1-й компилируется на моем IntelliJ.

Строго говоря, статические классы-члены не являются внутренними классами. Они называются вложенными классами.