【问题标题】:Declare enum without specify values, something like abstract声明枚举而不指定值,例如抽象
【发布时间】:2014-05-02 18:25:31
【问题描述】:

我有一个抽象类(或接口)。在这个类中我想定义一个枚举,以强制扩展这个抽象类(或实现这个接口)的类声明一个同名的枚举。

abstract class Operator {
    public abstract enum Symbol;
    public Symbol value;
}

class Binary extends Operator {
    public enum Symbol {
        pls,
        min,
        mul,
        div,
        //...
    }
}
class Unary extends Operator {
    public enum Symbol {
        sin,
        cos,
        tan,
        cot,
        //...
    }
}

假设我不知道子类枚举的值。我希望每个扩展类都有一个具有该名称及其值的枚举。我想使用枚举(特别是因为它很容易切换枚举)

【问题讨论】:

  • 有一种方法可以允许“用户指定”枚举,但我需要一点时间才能输入
  • 这个想法完全没有逻辑意义,并且表明对 enum 构造存在的原因存在根本的误解/缺乏理解
  • 我犹豫要不要打开这罐蠕虫,但泛型可以做到这一点。
  • enum 自动成为final 不能继承它
  • add values to enum 的可能重复项

标签: java enums abstract


【解决方案1】:

没有办法做这件事,而且,即使是,你会如何调用子类的实现?我的意思是,只有方法调用可以是virtual,即在运行时调度。类型不能,因此如果不使用反射作弊(无论如何都会抛弃任何类型安全,因此您甚至不需要子类化),您将无法调用 overridden 类型(实际上, 类型不能被覆盖)。

也许您仍然可以通过使用组合来实现您的目标:

public abstract class Operator<T extends Enum<T>> {
  public final Class<T> symbol;
  public Operator(Class<T> symbol) { this.symbol = symbol; }
}

public enum BinarySymbol { PLS, MIN, MUL, DIV }

public class Binary extends Operator<BinarySymbol> {
  public Binary(Object operand1, Object operand2, BinarySymbol symbol) {
    super(symbol);
  }
}

你的基类Operator可以通过反射动态读取枚举值,通过Class.getEnumConstants()

【讨论】:

    【解决方案2】:

    您不能在编译时强制执行它。一种方法是在运行时使用反射来查看类是否已正确实现。我不建议这样做,但这是可能的。

    【讨论】:

    • 这不是唯一的方法
    【解决方案3】:

    您可以做的是拥有实现通用接口的枚举,然后利用这些接口:

    public interface YourEnumInterface<E extends Enum<E> & YourEnumInterface<E>> {
    
        //methods that your enum should be implementing
    
    }
    

    接口泛型声明的扩展是为了保证它只被实现你的接口的枚举调用

    然后你必须指定的任何枚举都可以像这样实现它:

    public enum MyEnum implements YourEnumInterface<MyEnum> {
    
        // enum constants
        TEST_VALUE;
    
        // implementation of interface methods
    
    }
    

    从那里,您只需将 YourEnumInterface 作为一个对象,您可以为它们传递枚举值:

    public void doSomething(YourEnumInterface enm) {
        //work with enm
    }
    
    //Elsewheres...
    doSomething(MyEnum.TEST_VALUE);
    

    应该注意,一旦将枚举降低到接口本身,您将无法更改正在使用的常量(不进行强制转换,这可能是不安全的)。这实际上应该或多或少地用于将东西传递到仅与值一起使用的目的地(例如配置枚举或字符串的内部化等)

    因此与强制子类实现它相关:

    public class YourSuperClass {
        public abstract YourEnumInterface symbol;
    }
    

    一个可运行的例子

    public class EnumMagic {
    
        public static void main(String[] args) {
            YourSubClass clazz = new YourSubClass();
            //prints the default value
            System.out.println(clazz.getEnum().getValue());
            //gets the value of a specified enum constant
            System.out.println(clazz.getEnum().SECOND_TEST.getValue());
        }
    
    }
    
    abstract class YourSuperClass {
    
        protected YourEnumInterface symbol;
    
        public abstract YourEnumInterface getEnum();
    
    }
    
    interface YourEnumInterface<E extends Enum<E> & YourEnumInterface<E>> {
    
        public int getValue();
    
    }
    
    class YourSubClass extends YourSuperClass {
    
        public enum MyEnum implements YourEnumInterface<MyEnum> {
    
            TEST_VALUE(1),
            SECOND_TEST(2);
    
            private final int val;
    
            private MyEnum(int example) {
                this.val = example;
            }
    
            public int getValue() {
                return this.val;
            }
    
        }
    
        public YourSubClass() {
            this.symbol = MyEnum.TEST_VALUE;
        }
    
        public MyEnum getEnum() {
            return MyEnum.TEST_VALUE;
        }
    
    }
    

    这个程序的输出是:

    1
    2
    

    您可以通过getEnum 简单地获取类的指定枚举常量,它们将返回自己的内部枚举。

    但是,一旦向下转换为超级类型,例如YourSuperClass intc = clazz;,那么您将失去指定枚举本身的能力。根据您存储实例的方式,将确定这是否需要更改。

    【讨论】:

    • 这与enum 的实例在实现之间不同的问题无关
    • 除此之外,您可以让多个枚举实现相同的接口,然后互换使用它们...
    • 慢慢阅读理解的问题,他们想要一个没有值的enum,然后他们想用与方法或其他任何东西无关的特定实现来指定值这里。 Symbol.PLUS 是 Symbol 的一个实例 Symbol.SIN 是一个 Symbol 的实例。您对答案的尝试根本不允许在同一类型上这样做,因为它不能。
    • 正如 OP 所说:“在这个类中,我想定义一个枚举,以强制扩展这个抽象类(或实现这个接口)的类声明一个具有相同名称的枚举。” 这正是您完成此任务的方式。你不能按照你指定的方式去做,我澄清了,但我提供了一个可行的解决方案
    • 他们还希望能够获取 Symbol 的值实例,接口 不是枚举 它不能有值!他们希望该类型具有可访问的值。再次阅读以理解问题。显示一些执行我正在解释的编译和运行的代码,我会赞成这个答案,因为它不是问题的功能性答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多