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

2022-09-01 11:58:07

任务是用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();

} 

但是当提到我得到someField

无法对某个字段的非静态字段进行静态引用。

出了什么问题,是否有可能做得更好?


答案 1

专用的只不过是具有内类语义的子类。如果在编译后查看字节代码,您会注意到编译器仅插入用于读取私有字段的访问器方法,但任何专用枚举都编译为其自己的类。您可以将您的实现视为:enumenum

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

如您所见,会发生相同的编译器错误。实际上,您的问题与 s 无关,而是与它们的内部类语义有关。enum

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

  1. private成员不被继承。因此,当在超类中定义字段时,您无法从实例访问该字段。privatethis

  2. 对于内部类,即使外部类的成员是 ,也可以访问这些成员。这是由编译器通过将访问器方法插入到通过访问器方法公开字段的外部类来实现的。仅当内部类为非时,才能访问非字段。但是,对于 s,内部类始终是 。privateprivatestaticstaticenumstatic

后面的条件是编译器抱怨的内容:

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

您正在尝试从内部类访问非字段。即使由于内部类语义,该字段在技术上是可见的,这是不可能的。您可以显式指示编译器访问该值,方法是从超类中读取该值,例如:staticstatic

public String doIt() {
  MyEnum thiz = this;
  return thiz.someField;
}

现在,编译器知道您正在尝试访问可见(外部)类型的成员,而不是错误地访问(非静态)外部类实例(不存在)的字段。(类似地,您可以编写表达相同的想法,即您希望沿着继承链向下移动而不访问外部实例的字段。然而,更简单的解决方案是简单地使字段 。这样,编译器就会对继承可见性感到满意,并编译您的原始设置。someFieldsuper.someFieldprotected


答案 2

如果您将受保护而不是私有或改为使用,您将能够访问它。someFieldsuper.someField