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

时间:2023-01-26 14:29:09

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

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

The Sun documentation for Enums boldly states:

Enums的Sun文档大胆地指出:

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

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

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):

嗯,这是花花公子,但我需要为每个枚举提供一个常量数据类型表示,以便在switch语句中进行比较。情况如下:我正在构建将表示给定空间的节点,或迷宫图中的“槽”,并且这些节点必须能够从表示迷宫的2D整数数组构造。这是我为MazeNode类所获得的,这是目前问题所在(switch语句咆哮):

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.

注意:由于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;
    }

}

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?

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

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.

底线是我需要Enum具有相应的整数值,以便与程序中传入的2D整数数组进行比较。

7 个解决方案

#1


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

}

#2


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

}

#3


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.

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

#4


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.

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

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

#5


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

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

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

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

#6


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

#7


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.

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

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.).

旁注:一旦你习惯了这种思维(这与C的枚举引起的思维完全不同),你会发现你的代码中对“魔术数字”的需求要少得多。您只需指定枚举常量并在其上调用方法,而不是指定值然后赋予它一些含义。特别是,我的感觉是没有必要将每个枚举实例与一个值相关联(空为0,开始为1等)。

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

#1


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

}

#2


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

}

#3


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.

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

#4


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.

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

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

#5


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

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

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

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

#6


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

#7


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.

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

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.).

旁注:一旦你习惯了这种思维(这与C的枚举引起的思维完全不同),你会发现你的代码中对“魔术数字”的需求要少得多。您只需指定枚举常量并在其上调用方法,而不是指定值然后赋予它一些含义。特别是,我的感觉是没有必要将每个枚举实例与一个值相关联(空为0,开始为1等)。

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