Статический контекст в определении перечисления

Синтаксический сахар, предоставляемый средствами 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)

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

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

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

protected void helper(){
    // can be called from subclasses (such as FOO) since it is not private
}

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

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

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

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. Вот почему я считаю, что вы не можете получить доступ к helper (), потому что он частный. Так что this.helper (), вероятно, не должен работать. Я не уверен, почему работает даже super.helper (), но, возможно, enum дает вам частный доступ к родителю.

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

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

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

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