用Java编写枚举值表示的语句

时间:2009-06-27 06:36:56

标签: java enums switch-statement

我非常熟悉在其他语言中使用Enums,但我在Java中遇到了一些特殊用途的困难。

Enums的Sun文档大胆地说明:

  

“Java编程语言的枚举功能远远超过其他语言的功能,只不过是美化的整数。”

嗯,这很花哨,但我需要为每个枚举提供一个常量数据类型表示,以便在switch语句中进行比较。情况如下:我正在构建将代表给定空间的节点,或迷宫图中的“槽”,并且这些节点必须能够从表示迷宫的2D整数数组构造。这是我为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有相应的整数值,以便与程序中传入的2D整数数组进行比较。

7 个答案:

答案 0 :(得分:5)

您可以使用以下内容:

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

}

答案 1 :(得分:2)

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

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

}

答案 2 :(得分:1)

似乎没有简单的方法可以做你想做的事。常数必须是最终的,并在声明时分配;你不能在枚举成员中做的事情。

通过解决方案,我在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;
    }
}

答案 3 :(得分:1)

我和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);
}

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

考虑做这样的事情:

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

答案 6 :(得分:-2)

我不确定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;
   }
}