如何通过重写方法在java枚举中使用字段?

Mar*_*ark 29 java enums strategy-pattern

任务是用java实现漂亮的策略设计模式enum:

public enum MyEnum {

    FIRST {
        @Override
        public String doIt() {
            return "1: " + someField; //error
        }
    },
    SECOND {
        @Override
        public String doIt() {
            return "2: " + someField; //error
        }
    };

    private String someField;

    public abstract String doIt();

} 
Run Code Online (Sandbox Code Playgroud)

但是在提到someField我的时候

无法对someField的非静态字段进行静态引用.

有什么不对,有可能做得更好吗?

Raf*_*ter 27

一个专门enum的只是一个具有内部类语义的子类.如果在编译后查看字节代码,您会注意到编译器只插入访问器方法来读取私有字段,但任何专用的枚举都被编译为自己的类.您可以将您的enum实施视为:

public abstract class MyEnum {

  private static class First extends MyEnum {

    @Override
    public String doIt() {
        return "1: " + someField; //error
    }
  }

  private static class Second extends MyEnum {

    @Override
    public String doIt() {
        return "2: " + someField; //error
    }
  }

  public static final MyEnum FIRST = new First();
  public static final MyEnum SECOND = new Second();

  private String someField;

  public abstract String doIt();
} 
Run Code Online (Sandbox Code Playgroud)

如您所见,发生了相同的编译器错误.实际上,您的问题与enums 无关,而与其内部语义无关.

但是,您发现了编译器猜测您的代码意图的边缘情况,并试图警告您,您的意图是非法的.通常,该someField字段对于任何专业人员都是可见的enum.但是,有两种方法可以private从内部类访问该字段,只有一种是合法的:

  1. private成员不是继承的.因此,在超类中定义private字段this时,您无法访问实例中的字段.

  2. 对于内部类,外部类的成员即使是可访问的也是可访问的private.这是由编译器通过将访问器方法插入到外部类来实现的,这些外部类private通过访问器方法公开字段.static只有在内部类为非类时才能访问非字段static.对于enums,内部类总是如此static.

后来的条件是编译器抱怨的:

无法对非静态字段进行静态引用 someField

您正尝试staticstatic内部类访问非字段.即使由于内部类语义而在技术上可见字段,这也是不可能的.您可以通过例如从超类中读取它来明确地指示编译器访问该值:

public String doIt() {
  MyEnum thiz = this;
  return thiz.someField;
}
Run Code Online (Sandbox Code Playgroud)

现在,编译器知道您正在尝试访问可见(外部)类型的成员,而不是错误地访问someField(非静态)外部类实例(不存在)的字段.(类似地,您可以编写super.someField表达您想要继承链继承而不访问外部实例的字段的相同想法.)然而,更简单的解决方案是简单地创建字段protected.这样编译器就可以继承可见性并编译原始设置.


Ale*_*lex 5

如果您使用someFieldprotected而不是私有或使用,super.someField您将能够访问它.