Статический контекст в определении enum - PullRequest
11 голосов
/ 24 февраля 2009

Синтаксический сахар, предоставляемый Java enum, иногда может немного сбивать с толку. Рассмотрим пример, который не компилируется:

public enum TestEnum {

    FOO("foo") {
        public void foo() {
            helper();  // <- compiler error
        }
    };

    String name;
    TestEnum(String name) {
        this.name = name;
    }

    public abstract void foo();

    private void helper(){
        // do stuff (using this.name, so must not be static)
    }
}

Может кто-нибудь объяснить, почему компилятор говорит

На нестатический метод 'helper ()' нельзя ссылаться из статического контекста

Как именно этот контекст статичен?

Вы можете сделать эту компиляцию, изменив вызов на this.helper() (вот один запутанный момент: если мы действительно находимся в «статическом контексте», как предполагает компилятор, как можно » this «работа?» Или путем увеличения видимости helper() до уровня по умолчанию. Что бы вы предпочли? Кроме того, не стесняйтесь предложить лучший заголовок вопроса: -)

Редактировать : Я нашел некоторое обсуждение по этому поводу - но никаких реальных ответов. Мой коллега считает, что тот факт, что this.helper() работает, на самом деле является ошибкой компилятора. И действительно, с более новыми версиями Java кажется, что не работает (хотя super.helper() работает): «не может найти символ helper ()». (Хотя происходит что-то странное: после попытки с разными версиями Java я не могу заставить this.helper() скомпилировать снова с любой из них ...)

Ответы [ 5 ]

8 голосов
/ 28 февраля 2009

Сообщение об ошибке вводит в заблуждение, просто сделайте helper защищенным, и оно будет работать.

protected void helper(){
    // can be called from subclasses (such as FOO) since it is not private
}
3 голосов
/ 24 февраля 2009

Нечто подобное описано в книге Java Puzzlers. IIRC, контекст внешнего класса всегда рассматривается перед суперклассом. В этом случае помощник найден. Но мы строим значение в статическом контексте (фактически private static final перед FOO). Отсюда и ошибка.

Попробуйте super.helper();.

2 голосов
/ 24 февраля 2009

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

public abstract class TestEnum {

  public static final TestEnum FOO = new FOO("foo") {
    public void foo() {
        helper();  // <- compiler error
    }
 };

  String name;
  TestEnum(String name) {
      this.name = name;
  }

  public abstract void foo();

  private void helper(){
    // do stuff (using this.name, so must not be static)
  }

}

Экземпляр FOO - это любой класс, который расширяет TestEnum. Вот почему я считаю, что вы не можете получить доступ к помощнику (), потому что это личное. Так что this.helper (), вероятно, не должен работать. Я не уверен, почему даже super.helper () работает, но, возможно, enum дает вам частный доступ к родителю.

Что касается статической ошибки контекста, я согласен, что сообщение об ошибке не имеет смысла.

1 голос
/ 21 мая 2009

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

Разумное решение состоит в том, чтобы изменить метод доступа с private на protected , чтобы предоставить доступ к константе enum "подклассов".

Лучшее предложение для заголовка вопроса: "Java enum method?" или просто «Private enum method» (пусть Java-тег заботится о Java-сущности)

0 голосов
/ 24 февраля 2009

В статье упоминается эта проблема, к сожалению, она на немецком языке. Может быть, вы все еще можете извлечь некоторую полезную информацию.

РЕДАКТИРОВАТЬ: Кажется, это несколько другая проблема, чем у вас. Я до сих пор не понимаю поведение вашего примера, который я также вижу здесь.

...