Назначение метода public public enum Java
Итак, у меня есть enum
public enum Sample {
ValueA{
@Override
public String getValue(){ return "A"; }
},
ValueB{
@Override
public String getValue(){ return "B"; }
public void doSomething(){ }
};
abstract public String getValue();
};
и у меня есть другой код, пытающийся использовать перечисление.
Sample.ValueB.doSomething();
Кажется, что он должен быть действительным, но вызывает ошибку "Метод doSomething() - undefined для типа Sample". В отличие от
Sample value = Sample.ValueB;
value.doSomething();
который производит ту же ошибку и представляется разумным.
Я предполагаю, что есть разумный ответ о том, почему первый не работает, и он относится к двум примерам, эквивалентным под капотом. Я надеялся, что кто-то может указать мне на документацию о том, почему именно так.
Ответы
Ответ 1
Тип "поля" ValueA
равен Sample
. Это означает, что вы можете вызывать только методы на ValueA
, которые предоставляет Sample
. Из JLS §8.9.1. Константы контировки:
Методы экземпляров, объявленные в этих телах классов, могут вызываться вне охватывающего типа перечисления только в том случае, если они переопределяют доступные методы в охватывающем типе перечисления.
Что еще более важно: с точки зрения дизайна enum
значения должны быть одинаковыми: если какая-либо операция возможна с одним конкретным значением, тогда это должно быть возможно со всеми значениями (хотя это может привести к выполнению разного кода).
Ответ 2
В основном тип времени компиляции Sample.ValueB
по-прежнему является образцом, хотя тип времени выполнения для этого значения будет ValueB
. Таким образом, ваши два фрагмента кода эквивалентны - клиенты не видят "дополнительные" методы, которые присутствуют только в некоторых ваших значениях перечисления.
Вы можете эффективно подумать об enum как объявлении такого поля:
public static final Sample ValueB = new Sample() {
@Override
public String getValue(){ return "B"; }
public void doSomething(){ }
};
Ответ 3
Когда вы пишете
enum Sample
{
Value{
public void doSomething()
{
//do something
}
};
}
вы не создаете экземпляр Sample
enum, а скорее экземпляр анонимного подкласса enum Sample
. То, почему метод doSomething()
равен undefined.
Обновление: это можно доказать следующим образом:
Попробуйте это
System.out.println(Sample.ValueB.getClass().getName());
печатает Sample$2
Это означает, что даже если у вас есть метод doSomething()
в экземпляре Sample$2
, который вы назвали ValueB
, вы ссылаетесь на него через ссылку суперкласса типа Sample
и, следовательно, только те методы определенные в классе Sample
, будут видны во время компиляции.
Вы можете называть это doSomething()
во время выполнения посредством отражения.
Ответ 4
public void doSomething(){ }
будет иметь тот же эффект, что и private void doSomething(){ }
.
doSomething()
не отображается вне ValueB, если вы не добавите doSomething()
в Sample
.
Каждое значение Sample
имеет тип Sample
, поэтому он не может иметь различный набор методов для разных значений (с внешней точки зрения).