Java 中枚举值表示的 Switch 语句

发布于 2024-07-25 10:04:03 字数 1523 浏览 2 评论 0原文

我非常熟悉在其他语言中使用枚举,但在 Java 中的特定用途时遇到一些困难。

Sun 的枚举文档大胆地指出:

“Java 编程语言的枚举比其他语言中的对应枚举强大得多,而其他语言中的枚举只不过是美化的整数。”

好吧,那是花花公子,但出于 switch 语句中的比较原因,我需要为每个枚举提供一个常量数据类型表示。 情况如下:我正在构造代表给定空间或迷宫图中的“槽”的节点,并且这些节点必须能够从代表迷宫的二维整数数组构造。 这是我得到的 MazeNode 类,它是当前的问题所在(switch 语句咆哮):

注意:我知道由于 case 语句中的动态项,此代码不起作用。 它是为了说明我所追求的。

public class MazeNode
{
    public enum SlotValue
    {
        empty(0),
        start(1),
        wall(2),
        visited(3),
        end(9);

        private int m_representation;

        SlotValue(int representation)
        {
            m_representation = representation;
        }

        public int getRepresentation()
        {
            return m_representation;
        }
    }

    private SlotValue m_mazeNodeSlotValue;

    public MazeNode(SlotValue s)
    {
        m_mazeNodeSlotValue = s;
    }

    public MazeNode(int s)
    {

        switch(s)
        {
            case SlotValue.empty.getRepresentation():
                m_mazeNodeSlotValue = SlotValue.start;
                break;
            case SlotValue.end.getRepresentation():
                m_mazeNodeSlotValue = SlotValue.end;
                break;

        }
    }

    public SlotValue getSlotValue()
    {
        return m_mazeNodeSlotValue;
    }

}

因此,代码在 switch 语句上抱怨“case 表达式必须是常量表达式”——我可以理解为什么编译器可能会遇到麻烦,因为从技术上讲它们是动态的,但我不确定采取什么方法来解决这个问题。 有没有更好的办法?

最重要的是,我需要 Enum 具有相应的整数值,以便与程序中传入的二维整数数组进行比较。

I'm very familiar with using Enums in other languages, but I'm having some difficulty in Java with a particular use.

The Sun documentation for Enums boldly states:

"Java programming language enums are far more powerful than their counterparts in other languages, which are little more than glorified integers."

Well, that's dandy, but I kind of need to have a constant datatype representation for each of the Enums, for comparison reasons in a switch statement. The situation is as follows: I'm constructing nodes which will represent a given space, or 'slot' in a maze graph, and these nodes must be able to be constructed from a 2D integer array which represents the maze. Here's what I've got for the MazeNode class, which is currently where the problem is (the switch statement barks):

NOTE: I know this code does not function, due to the dynamic item in the case statement. It is there to illustrate what I'm after.

public class MazeNode
{
    public enum SlotValue
    {
        empty(0),
        start(1),
        wall(2),
        visited(3),
        end(9);

        private int m_representation;

        SlotValue(int representation)
        {
            m_representation = representation;
        }

        public int getRepresentation()
        {
            return m_representation;
        }
    }

    private SlotValue m_mazeNodeSlotValue;

    public MazeNode(SlotValue s)
    {
        m_mazeNodeSlotValue = s;
    }

    public MazeNode(int s)
    {

        switch(s)
        {
            case SlotValue.empty.getRepresentation():
                m_mazeNodeSlotValue = SlotValue.start;
                break;
            case SlotValue.end.getRepresentation():
                m_mazeNodeSlotValue = SlotValue.end;
                break;

        }
    }

    public SlotValue getSlotValue()
    {
        return m_mazeNodeSlotValue;
    }

}

So the code complains on the switch statement with "case expressions must be constant expressions" -- I can see why the compiler might have trouble, since technically they are dynamic, but I'm not sure what approach to take to resolve this. Is there a better way?

The bottom line is I need the Enum to have corresponding integer values for comparison against the incoming 2D array of integers in the program.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

彼岸花似海 2024-08-01 10:04:03

你可以使用这样的东西:

import java.util.HashMap;
import java.util.Map;

public class MazeNode {

    public enum SlotValue {
        empty(0), start(1), wall(2), visited(3), end(9);

        protected int m_representation;

        SlotValue(int representation) {
            m_representation = representation;

        }

        private static final Map<Integer, SlotValue> mapping = new HashMap<Integer, SlotValue>();

        static {
            for (SlotValue slotValue : SlotValue.values()) {
                mapping.put(slotValue.m_representation, slotValue);
            }
        }

        public static SlotValue fromRepresentation(int representation) {
            SlotValue slotValue = SlotValue.mapping.get(representation);
            if (slotValue == null)
                // throw your own exception
                throw new RuntimeException("Invalid representation:" + representation);
            return slotValue;
        }
    }

    private SlotValue m_mazeNodeSlotValue;

    public MazeNode(SlotValue s) {
        m_mazeNodeSlotValue = s;
    }

    public MazeNode(int s) {
        m_mazeNodeSlotValue = SlotValue.fromRepresentation(s);

    }

    public SlotValue getSlotValue() {
        return m_mazeNodeSlotValue;
    }

    public static void main(String[] args) {
        MazeNode m = new MazeNode(2);
        System.out.println(m.getSlotValue());
        m = new MazeNode(9);
        System.out.println(m.getSlotValue());
    }

}

You can use something like this:

import java.util.HashMap;
import java.util.Map;

public class MazeNode {

    public enum SlotValue {
        empty(0), start(1), wall(2), visited(3), end(9);

        protected int m_representation;

        SlotValue(int representation) {
            m_representation = representation;

        }

        private static final Map<Integer, SlotValue> mapping = new HashMap<Integer, SlotValue>();

        static {
            for (SlotValue slotValue : SlotValue.values()) {
                mapping.put(slotValue.m_representation, slotValue);
            }
        }

        public static SlotValue fromRepresentation(int representation) {
            SlotValue slotValue = SlotValue.mapping.get(representation);
            if (slotValue == null)
                // throw your own exception
                throw new RuntimeException("Invalid representation:" + representation);
            return slotValue;
        }
    }

    private SlotValue m_mazeNodeSlotValue;

    public MazeNode(SlotValue s) {
        m_mazeNodeSlotValue = s;
    }

    public MazeNode(int s) {
        m_mazeNodeSlotValue = SlotValue.fromRepresentation(s);

    }

    public SlotValue getSlotValue() {
        return m_mazeNodeSlotValue;
    }

    public static void main(String[] args) {
        MazeNode m = new MazeNode(2);
        System.out.println(m.getSlotValue());
        m = new MazeNode(9);
        System.out.println(m.getSlotValue());
    }

}
心安伴我暖 2024-08-01 10:04:03

其他建议的另一种方法是您可以在枚举构造函数中输入值,而不必随后循环:

public class MazeNode {
    private static final Map<Integer, SlotValue> mapping = new HashMap<Integer, SlotValue>();

    enum SlotValue {
        empty(0),start(1),wall(2),visited(3),end(9);

        private final int m_representation;

        SlotValue(int representation) {
            m_representation = representation;
            mapping.put(Integer.valueOf(representation), this);
        }

    }

    SlotValue getSlotValue(int representation) {
        return mapping.get(Integer.valueOf(representation));
    }

}

An alternate approach to the other suggestions is that you can enter the values in the enum constructors rather than having to loop over afterwards:

public class MazeNode {
    private static final Map<Integer, SlotValue> mapping = new HashMap<Integer, SlotValue>();

    enum SlotValue {
        empty(0),start(1),wall(2),visited(3),end(9);

        private final int m_representation;

        SlotValue(int representation) {
            m_representation = representation;
            mapping.put(Integer.valueOf(representation), this);
        }

    }

    SlotValue getSlotValue(int representation) {
        return mapping.get(Integer.valueOf(representation));
    }

}
桃气十足 2024-08-01 10:04:03

似乎没有简单的方法可以做你想做的事。 常量必须是最终常量并在声明时赋值; 您不能在枚举成员中执行某些操作。

通过解决方案,我向 SlotValue 枚举添加了静态decode() 方法。 这会比较每个 SlotValue 的 m_representation 字段并返回第一个匹配项。 它会起作用,并且可能不是最有效的方法,但它只需要几行代码即可完成工作。

public class MazeNode {
    public enum SlotValue {
        empty(0),
        start(1),
        wall(2),
        visited(3),
        end(9);

        private int m_representation;

        SlotValue(int representation) {
            m_representation = representation;
        }

        private static SlotValue decode( int in ) {
            for ( SlotValue slot : values() ) {
                if ( slot.m_representation == in ) {
                    return slot;
                }
            }
            return empty;
        }
    }

    private SlotValue m_mazeNodeSlotValue;

    public MazeNode(SlotValue s) {
        m_mazeNodeSlotValue = s;
    }

    public MazeNode(int s) {
        m_mazeNodeSlotValue = SlotValue.decode( s );
    }

    public SlotValue getSlotValue() {
        return m_mazeNodeSlotValue;
    }
}

It appears that there's no easy way to do what you want. Constants must be both final and assigned when they're declared; something you cannot do in the member of an enum.

By way of a solution I've added a static decode() method to the SlotValue enum. This does a comparison of each SlotValue's m_representation field and returns the first match. It'll work, and it might not be the most efficient approach, but it does the job in only a few lines of code.

public class MazeNode {
    public enum SlotValue {
        empty(0),
        start(1),
        wall(2),
        visited(3),
        end(9);

        private int m_representation;

        SlotValue(int representation) {
            m_representation = representation;
        }

        private static SlotValue decode( int in ) {
            for ( SlotValue slot : values() ) {
                if ( slot.m_representation == in ) {
                    return slot;
                }
            }
            return empty;
        }
    }

    private SlotValue m_mazeNodeSlotValue;

    public MazeNode(SlotValue s) {
        m_mazeNodeSlotValue = s;
    }

    public MazeNode(int s) {
        m_mazeNodeSlotValue = SlotValue.decode( s );
    }

    public SlotValue getSlotValue() {
        return m_mazeNodeSlotValue;
    }
}
热鲨 2024-08-01 10:04:03

我同意 olliej 你应该接受吸气剂。 Java(与 C# 不同)不允许您在原语(在您的情况下为 int)和枚举之间进行转换。 内部表示(此处为 m_representation)只是另一个字段,而不是可访问的常量。

这是好(真正类型安全)还是坏(更难序列化和反序列化等)取决于您如何看待它。 下面的方法显然不如交换机有效,但我相信这是避免冗余的唯一方法。

您可能意识到,最好尽可能将数据保留为枚举形式。

public enum SlotValue
{
    empty(0),
    start(1),
    wall(2),
    visited(3),
    end(9);

    private int m_representation;

    SlotValue(int representation)
    {
        m_representation = representation;
    }

    public static SlotValue fromInt(int intSerialization)
    {
        for(SlotValue sv : SlotValue.values())
            if(sv.m_representation == intSerialization)
                return sv;
        return null;
    }
}

private SlotValue m_mazeNodeSlotValue;

public MazeNode(SlotValue s)
{
    m_mazeNodeSlotValue = s;
}

public MazeNode(int s)
{
    m_mazeNodeSlotValue = SlotValue.fromInt(s);
}

I'm with olliej that you should probably accept a getter. Java (unlike C#) does not allow you to cast between a primitive (int in your case) and a enum. The internal representation (m_representation here) is just another field, not an accessible constant.

This is good (genuinely type-safe) or bad (harder to serialize and deserialize, among other things) depending how you look at it. The method below obviously is not as efficient as a switch, but I believe it's the only way to avoid redundancy.

As you probably realize, it's best to keep the data in enum form as much as possible.

public enum SlotValue
{
    empty(0),
    start(1),
    wall(2),
    visited(3),
    end(9);

    private int m_representation;

    SlotValue(int representation)
    {
        m_representation = representation;
    }

    public static SlotValue fromInt(int intSerialization)
    {
        for(SlotValue sv : SlotValue.values())
            if(sv.m_representation == intSerialization)
                return sv;
        return null;
    }
}

private SlotValue m_mazeNodeSlotValue;

public MazeNode(SlotValue s)
{
    m_mazeNodeSlotValue = s;
}

public MazeNode(int s)
{
    m_mazeNodeSlotValue = SlotValue.fromInt(s);
}
故事灯 2024-08-01 10:04:03

所有语言(JS 除外,因为它太疯狂了 :D )都要求 switch 语句是常量表达式。

你想做什么? 通过向 SlotValue 添加 getter,您可以轻松地从 SlotValue 转换为 int。

All languages (with the exception of JS because it's insane :D ) require switch statements to be constant expressions.

What are you trying to do? You can easily go from SlotValue to int by adding a getter to SlotValue.

伏妖词 2024-08-01 10:04:03

考虑做这样的事情:

public class Node {
    public enum Slot {
        empty, start, wall, visited, end;
        static Slot fromInt(int s) {
            for (Slot slot : Slot.values())
                if (slot.ordinal() == s)
                    return slot;
            throw new RuntimeException("" + s + " is illegal value!");
        }
    }
    public Node(Slot slot) {
        this.slot = slot;
    }
    public Node(int s) {
        this(Slot.fromInt(s));
        switch(slot) {
            case empty: /* special stuff for empty */ break;
            case start: /* special stuff for start */ break;
            /* ... */
        }
    }
    private Slot slot;
}

consider doing something like this:

public class Node {
    public enum Slot {
        empty, start, wall, visited, end;
        static Slot fromInt(int s) {
            for (Slot slot : Slot.values())
                if (slot.ordinal() == s)
                    return slot;
            throw new RuntimeException("" + s + " is illegal value!");
        }
    }
    public Node(Slot slot) {
        this.slot = slot;
    }
    public Node(int s) {
        this(Slot.fromInt(s));
        switch(slot) {
            case empty: /* special stuff for empty */ break;
            case start: /* special stuff for start */ break;
            /* ... */
        }
    }
    private Slot slot;
}
故事↓在人 2024-08-01 10:04:03

我不确定 SlotValue 在您的程序中的用途是什么,但似乎您没有充分利用它们的能力。 您可以调用枚举实例上的方法或查询其状态。 因此,您可以将枚举值的开关转换为方法调用/状态查询,如下所示。

旁注:一旦您习惯了这种思维(这与 C 枚举引发的思维完全不同),您就会意识到代码中对“幻数”的需求要少得多。 您只需指定枚举常量并调用它的方法,而不是指定一个值然后赋予它一些含义。 具体来说,我的感觉是,没有真正需要将每个枚举实例与一个值关联起来(空是 0,开始是 1 等)。

无论如何,这是代码:

public class MazeNode
{
   public enum SlotValue
   {
       empty(0),
       start(1),
       wall(2),
       visited(3),
       end(9);

       private int m_representation;

       SlotValue(int representation)
       {
           m_representation = representation;
       }

       public int getRepresentation()
       {
           return m_representation;
       }

       private SlotValue next = null;

       static
       {
          empty.next = start;
          end.next = end;
       }
   }


   private SlotValue m_mazeNodeSlotValue;

   public MazeNode(SlotValue s)
   {
       m_mazeNodeSlotValue = s;
   }

   public MazeNode(int s)
   {
       m_mazeNodeSlotValue = SlotValue.values()[s].next;
   }

   public SlotValue getSlotValue()
   {
       return m_mazeNodeSlotValue;
   }
}

I am not sure what's the purpose of SlotValue in your program but it seems that you are not using their full power. You can invoke methods on enum instances or query their state. Thus you translate a switch on enum value into method invocation/state querying, as show below.

Side note: Once you get used to this kind of thinking (which is quite different from the thinking induced by C's enums) you realize that there's much less need for "magic numbers" in your code. Instead of specifying an value and then giving it some meaning you just specify the enum constant and invoke methods on it. Specifcially, my feeling is that there's no real need for associating each of your enum instances with a value (empty is 0, start is 1, etc.).

Anyway, here's the code:

public class MazeNode
{
   public enum SlotValue
   {
       empty(0),
       start(1),
       wall(2),
       visited(3),
       end(9);

       private int m_representation;

       SlotValue(int representation)
       {
           m_representation = representation;
       }

       public int getRepresentation()
       {
           return m_representation;
       }

       private SlotValue next = null;

       static
       {
          empty.next = start;
          end.next = end;
       }
   }


   private SlotValue m_mazeNodeSlotValue;

   public MazeNode(SlotValue s)
   {
       m_mazeNodeSlotValue = s;
   }

   public MazeNode(int s)
   {
       m_mazeNodeSlotValue = SlotValue.values()[s].next;
   }

   public SlotValue getSlotValue()
   {
       return m_mazeNodeSlotValue;
   }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文