Вызов метода перечисления
У меня есть следующее перечисление:
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
, он будет работать нормально. Почему?
Ответы
Ответ 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
.