【问题标题】:enum's constant value adding onymous class枚举的常量值添加匿名类
【发布时间】:2019-02-23 19:25:04
【问题描述】:

在枚举的常量值声明的类体中加入匿名(非匿名)类方法有什么用?

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;
    }

我如何访问/执行这样的方法?我找了anonymous class的例子,不推荐

作为建议,让您的枚举实现您的接口以使代码更具可读性

我在JLS 的枚举常量部分没有找到用法

枚举常量的可选类主体隐式定义了一个匿名类声明(第 15.9.5 节),它扩展了直接封闭的枚举类型。类主体受匿名类的常规规则管理;特别是它不能包含任何构造函数。

在这些类主体中声明的实例方法可以在封闭枚举类型之外调用只有当它们覆盖封闭枚举类型中的可访问方法时

【问题讨论】:

  • enum 常量体内的嵌套类型的用例与任何其他类体内的用例相同。仅仅因为它们有名字,它们就不需要从外部访问。与任何其他类一样,它们仍然可以在声明范围内按名称引用。引用的段落没有说明这种嵌套类型声明,只是因为没有什么特别需要说明的。

标签: java enums anonymous-class


【解决方案1】:

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();
    }
}

在这两种情况下,内部类本身对外部代码是不可见的,只有在枚举常量内部,如果枚举常量的实现变得如此复杂以至于需要一个命名的内部类,我肯定会重构它,例如通过将复杂性委托给一些普通的顶级类。

【讨论】:

  • 感谢您的回答,但是您的代码似乎类似于使用匿名类,不是吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 2011-08-17
  • 2011-11-01
  • 2015-08-21
相关资源
最近更新 更多