当前位置: 首页 > 知识库问答 >
问题:

为什么switch case语句不能处理枚举的属性?

梁丘安晏
2023-03-14

我正在编写一个简单的游戏,在其中我使用一个枚举,CommandManager,来存储关于可能的命令以及每个命令的作用的信息。此枚举的主要目的是能够打印出可用命令的菜单,以及用于检查输入并执行与该输入相关的操作。我的问题在于第二次使用,我使用switch语句根据用户的输入确定用户想要做什么。当尝试使用枚举的属性(通过getter方法)作为案例标签时,我遇到了一个编译错误。提供的错误消息是,大小写表达式必须是常量表达式。鉴于CommandManager的属性被声明为final,我认为枚举的属性根本不能在switch语句中使用,对吗?如果是这样,为什么?

以下代码的简化版本,以防出错。

方法代码:

void interpretInput()   {
    String command = input.getInput();
    if (command.length() == 2)  {
            switch (command) {
            case CommandManager.MAINMENU.getCommand(): goToMainMenu(); 
                    break;
            case CommandManager.NEWGAME.getCommand(): startNewGame();
                    break;
            case CommandManager.LISTGAMES.getCommand(): listSavedGames();
                    break;
            case CommandManager.EXITGAME.getCommand(): exitGame();
                    break;
            case CommandManager.HELPMENU.getCommand(): listAllCommands();
                    break;
            }
    }
}

枚举代码:

public enum CommandManager {

NEWGAME("!n", "New game"),
MAINMENU("!m", "Go to main menu"),
EXITGAME("!q", "Exit Battleships"),
LISTGAMES("!g", "List saved games"),
HELPMENU("!h", "Open help menu"),
LOADGAME("!l", "Load a new game"),
SAVEGAME("!s", "Save current game");

private final String command;
private final String menuOption;

CommandManager(String aCommand, String anOption)    {
    command = aCommand;
    menuOption = anOption;
}

String getCommand() {
    return command;
}

String getMenuOption()  {
    return menuOption;
}
}

共有3个答案

文心思
2023-03-14

我会通过使用Map来帮助动作设计模式来做不同的事情。

首先在CommandManager枚举中添加一个方法,该方法将命令字符串转换为CommandManager对象,例如:

public static CommandManager getCommandManager(String command) {
    for (CommandManager cManager : CommandManager.values()) {
        if (command.equals(cManager.getCommand())) {
            return cManager;
        }
    }
    throw new IllegalArgumentException(command);
}

例如,

public enum CommandManager {

    NEWGAME("!n", "New game"), 
    MAINMENU("!m", "Go to main menu"), 
    EXITGAME("!q", "Exit Battleships"), 
    LISTGAMES("!g", "List saved games"), 
    HELPMENU("!h", "Open help menu"), 
    LOADGAME("!l", "Load a new game"), 
    SAVEGAME("!s", "Save current game");

    private final String command;
    private final String menuOption;

    CommandManager(String aCommand, String anOption) {
        command = aCommand;
        menuOption = anOption;
    }

    String getCommand() {
        return command;
    }

    String getMenuOption() {
        return menuOption;
    }

    // ************ ADD THIS! *******
    public static CommandManager getCommandManager(String command) {
        for (CommandManager cManager : CommandManager.values()) {
            if (command.equals(cManager.getCommand())) {
                return cManager;
            }
        }
        throw new IllegalArgumentException(command);
    }
}

然后,为使用该映射的代码提供一个映射,该映射将每个CommandManager映射为一个Runnable,并填充该映射:

public class TestEnum {
    private Map<CommandManager, Runnable> commandMap = new EnumMap<>(CommandManager.class);

    public TestEnum() {
        commandMap.put(CommandManager.MAINMENU, () -> goToMainMenu());
        commandMap.put(CommandManager.MAINMENU, () -> goToMainMenu());
        commandMap.put(CommandManager.NEWGAME, () -> startNewGame());
        commandMap.put(CommandManager.LISTGAMES, () -> listSavedGames());
        commandMap.put(CommandManager.EXITGAME, () -> exitGame());
        commandMap.put(CommandManager.HELPMENU, () -> listAllCommands());
    }

然后使用它!

void interpretInput(String command) {
    CommandManager cManager = CommandManager.getCommandManager(command);
    commandMap.get(cManager).run();
}
曹骞仕
2023-03-14

你必须使用一些不同的方法。您可以在枚举内编写静态方法,将命令字符串转换为CommandManager枚举:

public static CommandManager fromCommand(String command) {
    for (CommandManager commandManager : values()) {
        if (commandManager.getCommand().equals(command)) {
            return commandManager;
        }
    }
    return null; // or throw exception, whatever fits best for your code
}

然后,您可以调用此方法来获取en enum对象,并使用switch语句执行任何您想要的操作:

String command = input.getInput();
CommandManager commandManager = CommandManager.fromCommand(command);
if (commandManager != null)  {
    switch (commandManager) {
        case MAINMENU: 
            goToMainMenu();
            break;
        case NEWGAME: 
            startNewGame();
            break;
        case LISTGAMES: 
            listSavedGames();
            break;
        case EXITGAME: 
            exitGame();
            break;
        case HELPMENU: 
            listAllCommands();
            break;
        default:
            throw new IllegalArgumentException("Unknown command: " + commandManager);
    }
}
应志用
2023-03-14

我认为枚举的属性不能用在开关语句中,这是对的吗?

你是。

如果是这样,为什么?

因为switch语句的“标签”需要是编译时常数,并且枚举的属性不符合条件。

它们需要是编译时常量的原因是编译器需要检查开关标签是否不同。它不允许这样的事情

switch (someValue) {
    case A.method():  doA();
    case B.method():  doB();
}

其中<代码>A。方法()和。结果表明,method()具有相同的值。如果事例表达式不是编译时常量表达式,则编译器无法检测到问题。(方法调用从来不是编译时常量表达式。)

 类似资料:
  • 问题内容: (注:编辑过的问题;先前的意图不明确) 考虑以下代码: 此代码可以正常工作。 但是,如果我替换: 与: 然后编译器抱怨: java:/path/to/Foo.java:whatever:枚举开关大小写标签必须是枚举常量的非限定名称 (要求内联常量的一个原因是switch语句在每种情况下都需要常量,并且两个这样的常量值可能都不相同。编译器在编译时检查switch语句中是否有重复的常量值;

  • (注:经编辑的问题;事先意图不明确) 与: 在JLS的什么地方定义了语句中的值必须以这种方式编写?

  • 问题内容: 我正在使用JavaScript将对象序列化为JSON字符串, 我注意到只有可枚举的对象属性才被序列化: [ 笔 ] 我想知道为什么会这样?我已经通过搜索MDN页面中,json2解析器文档。我找不到任何地方记录此行为。 我怀疑这是使用仅通过[[enumerable]]属性的循环(至少在情况下)的结果。可以使用类似的方法同时返回可枚举和不可枚举的属性。不过,这可能会导致序列化(由于反序列化

  • 问题内容: 我想知道为什么在Java语言中a 不能扩展。 我不是在谈论一个延伸的(这不能做,因为Java没有多重继承,而Š隐含延长),但一类的以只添加额外的方法,而不是额外的枚举值。 就像是: 要这样使用: 因此,有人可以对此限制提供理由(或将我指向正确的JLS部分)吗? 问题答案: 我认为 他们这样做 的答案来自以下问题: 在您的示例中,如何实例化MyClass?用户永远不会(通过)显式实例化枚

  • 问题内容: Java不允许枚举位于接口内部,但是默认情况下,接口内部的每个数据成员都是。有人可以澄清吗? 问题答案: 枚举不能是最终的,因为编译器将为程序员明确为其定义实现的每个枚举条目生成子类。 此外,根据JLS第8.9节,没有实例具有自己的类主体的枚举是隐式最终的。

  • 编译器声称 的末尾缺少一个返回语句。代码如下: 编译器是否正确?(Android Studio) 如果是这样,在什么情况下可以到达方法的末尾?我认为不能是并且所有枚举都包含在开关语句中,在任何情况下返回语句都会离开方法。不能是,因为方法如果结果是,则会引发异常。 如果没有,你会用< code > return null//never behind 标记方法的(希望)不可到达的一端,还是抛出一个<