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 的实现足够复杂,需要一个内部类)。一般来说,我希望枚举常量不要变得那么复杂,但这是风格问题。
只有通过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();
}
}
在这两种情况下,内部类本身对外部代码是不可见的,只有在枚举常量内部,如果枚举常量的实现变得如此复杂以至于需要一个命名的内部类,我肯定会重构它,例如通过将复杂性委托给一些普通的顶级类。