Подтвердить что ты не робот

Вызов метода перечисления

У меня есть следующее перечисление:

 enum Days{
    TODAY{
        @Override
        public Date getLowerBound(){
            another();             //1
            currentUpperBound();   //2
            return null;
        }

        @Override
        public Date another() {
            return null;
        }
    };

    public abstract Date getLowerBound();

    public abstract Date another();

    private Date currentUpperBound(){
        return null;
    }
}

Почему //2 вызывает ошибку времени компиляции с помощью

Cannot make a static reference to the non-static method 
currentUpperBound() from the type Days

Но //1 компилируется отлично? Оба метода нестатические. Я не вижу никакой проблемы... Может быть, это имеет какое-то отношение к Eclipse?

ОБНОВЛЕНИЕ: Как заметил в комментарии @Florian Schaetz, если мы объявим метод с модификатором static private, он будет работать нормально. Почему?

4b9b3361

Ответ 1

Я предлагаю создать currentUpperBounds() protected вместо private. Другим решением будет префикс вашего вызова с помощью super., который также работает:

@Override
public Date getLowerBound(){
   another();
   super.currentUpperBound();
   return null;
}

Кроме того, СЕГОДНЯ также работает:

@Override
public Date getLowerBound(){
   another();
   TODAY.currentUpperBound();
   return null;
}

Mick Mnemonic упомянул отличный ответ в этом дубликате, что объясняет это довольно красиво.

Ответ 2

TL; DR

Решение вашей проблемы

Я предлагаю сделать currentUpperBound() метод protected.

Почему?

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

Понимание перечисления за сценой

Кодовая эквивалентность

Чтобы показать код, как работает перечисление 1:

public enum MyEnum {
    JESSE {
       @Override
       public void sayMyName() {
           System.out.println("Pinkman");
       }
    }, WALTER;

    public void sayMyName() {
        System.out.println("Heisenberg");
    }

    private void unreachableMethod() {
        // try again
    }
}

(почти) эквивалентно:

public class MyEnum {
    private static final MyEnum JESSE = new MyEnum() {
       @Override
       public void sayMyName() {
           System.out.println("Pinkman");
       }
    };
    private static final MyEnum WALTER = new MyEnum();

    public void sayMyName() {
        System.out.println("Heisenberg");
    }

    private void unreachableMethod() {
        // try again
    }
}

Когда вы пишете это так, некоторые вещи становятся намного понятнее:

- почему == работает для проверки равенства перечисления

Только один указатель на одно значение. Object equals(Object) здесь совершенен, поскольку он проверяет только это.

- почему вы можете наследовать методы из MyEnum или access private static, но не private нестатические методы

  • Значения хранятся в виде полей static, поэтому они не могут получить доступ к контексту экземпляра.
  • Значение наследует MyEnum, поэтому им доступно все, доступное через наследство.

Почему я сказал, что это почти эквивалентно?

Есть несколько дополнительных элементов управления, встроенных в механизм перечисления.

Например, switch может указать, было ли у вас case для каждого значения для перечисления: попробуйте проверить только некоторые значения и не определять default, компилятор поднимет предупреждение. Это было бы невозможно, если бы вы просто использовали абстрактный класс с константами.

Метод values() также показывает, что вещи более развиты, чем мой простой пример, но я думаю, что это помогает понять.


1 на основе моего понимания JSL

Ответ 3

Вы можете объявить метод currentUpperBound как abstract и реализовать его в своих экземплярах или оставить его вне себя.

В обоих случаях вы должны объявить его с помощью модификатора доступа не private.

Сообщение об ошибке компилятора здесь довольно запутанно. Предполагается, что currentUpperBound должен быть static, который предоставит вам доступ из экземпляров, даже если метод объявлен как private.