TL; DR Трудно представить реальную ситуацию, когда определение внутреннего класса внутри константы перечисления имеет смысл.
Давайте начнем с вашего примера кода ...
public enum Status {
SUCCESS("SUCCESS") {
},
FAILED("FAILED") {
class Test {
public void test() {
System.out.println("test");
}
}
};
private String code;
Status(String code) {
this.code = code;
}
}
Поскольку FAILED
является значением перечисления с телом, оно становится анонимным подклассом класса перечисления Status
.И Test
определен внутри этого анонимного класса.Из-за анонимной природы включающего его класса нет способа выразить его имя за пределами FAILED
.Конечно, это не Status.FAILED.Test
.
Так что Test
в основном полезен внутри FAILED
(если реализация FAILED
достаточно сложна, чтобы гарантировать внутренний класс).Как правило, я бы предпочел, чтобы константы enum не становились такими сложными, но это вопрос стиля.
Доступ к Test
извне FAILED
возможен только через суперкласс или интерфейс, который Test
расширяет / реализует и только для методов, предоставляемых через этот суперкласс или интерфейс.
(Придуманный) пример, показывающий использование как внутри, так и за пределами FAILED
, может быть:
public class StatusTest {
enum Status {
FAILED{
class Test implements Runnable {
private String text = "Test " + System.currentTimeMillis();
@Override
public void run() {
System.out.println(text);
}
}
@Override
public Runnable getRunner() {
return new Test();
}
@Override
public void message() {
getRunner().run();
}
};
public abstract void message();
public abstract Runnable getRunner();
}
public static void main(String[] args) {
Status status = Status.FAILED;
status.message();
Runnable runner = status.getRunner();
runner.run();
}
}
(Добавлено позже)
Конечно, в этом примере нет причин, по которым Runnable должен получить имя класса.Я бы обычно использовал именованный внутренний класс вместо анонимного, только если он
- используется в нескольких местах или
- настолько сложен, что делает метод включения нечитаемым.
Это всегда одно и то же решение при представлении анонимного или именованного внутреннего класса.С перечислениями есть еще меньше причин давать внутреннему классу имя, так как это имя нельзя использовать снаружи.Итак, если бы я увидел код, подобный описанному выше, я бы реорганизовал его для использования анонимного класса:
public class StatusTest {
enum Status {
FAILED {
@Override
public Runnable getRunner() {
return new Runnable() {
private String text = "Test " + System.currentTimeMillis();
@Override
public void run() {
System.out.println(text);
}
};
}
@Override
public void message() {
getRunner().run();
}
};
public abstract void message();
public abstract Runnable getRunner();
}
public static void main(String[] args) {
Status status = Status.FAILED;
status.message();
Runnable runner = status.getRunner();
runner.run();
}
}
В обоих случаях сам внутренний класс не виден внешнему коду, только внутриконстанту enum, и если реализация константы enum становится настолько сложной, что она требует именованного внутреннего класса, я бы, конечно, реорганизовал ее, например, делегировав сложность некоторому обычному классу верхнего уровня.