【问题标题】:Setting an enum by using an int specific to that enum?通过使用特定于该枚举的 int 来设置枚举?
【发布时间】:2011-09-07 10:18:22
【问题描述】:

大家好。所以我有一组枚举和一个带有与这些枚举对应的整数的数据库。像这样的东西,例如:

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }
}

我还有一个数据库,它只通过整数引用这些天,这对应于它们在上面设置的枚举中的 int。我要做的是查询一个数据库,它将返回一个整数,然后根据从数据库返回的整数将一个枚举器设置为一个对象。我可以这样做:

public static Day getDay(int i) {
    switch(i) {
    case 1:
        return Day.SUNDAY;
    case 2: 
        return Day.MONDAY;
    //And so on
    }
}

但是对于一个包含超过 100 个枚举的枚举集,这似乎不太实用。

那么有没有办法做到这一点?同样,我的目标是简单地插入一个 int 值并取回一个枚举器,而不必为此集中的许多枚举创建一个新方法。也许我应该让它成为自己的类而不是枚举器,但我希望这样做。谢谢!

【问题讨论】:

标签: java enums


【解决方案1】:

下面是一个可行的简单实现:

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }

    public static Day forInt(int id) {
        for (Day day : values()) {
            if (day.fId == id) {
                return day;
            }
        }
        throw new IllegalArgumentException("Invalid Day id: " + id);
    }
}

如果你知道你的枚举从 1 开始计数,你可以简单地使用它来代替:

public static Day forInt(int id) {
    return values()[id - 1];
}

【讨论】:

    【解决方案2】:

    枚举有一个内置的 ID 号,即“序数”,您可以将其用于此目的,只要您有一种简单的方法可以从表示数据库中给定值的数字获取到枚举。序号按照它们在源文件中声明的顺序分配给枚举值,从 0 开始,因此在您的示例中,SUNDAY 的序号为 0,MONDAY 的序号为 1,等等。

    为了使用它,您只需要将存储在数据库中的整数转换为其对应的序数,然后将其用于access the enum value。因此,对于您的示例,实现可能是

    private static Day[] values = Day.values();
    public static Day getDay(int i) {
        return values[i - 1];
    }
    

    如果枚举值根据其数据库 ID 的顺序与它们在源代码中声明的顺序相同,那么您几乎可以按原样使用上述方法(除了更改类名) .否则,您可能需要做一些更复杂的事情来将数据库值映射到序数;如果映射是高度非线性的,也许可以设置一个数组。

    附:当然,如果您这样做,fId 字段将毫无用处。

    【讨论】:

    • values() 是一种方法而不是字段。代码需要是:return values()[i - 1]; (不是返回值 [i - 1];)。注意“值”后面的括号
    • 这种方法的问题是很容易通过在中间添加一个新的枚举值来意外破坏排序。如果您只在运行时使用这些值,那没关系,但在这种情况下,OP 表示它们必须与外部数据库保持同步。
    • @Bohemian:不,EnumClass.values() 是一种方法。 values 是我在代码示例的第一行中定义的字段。 (请注意,此代码示例不是枚举类本身的一部分)
    • @Matt:是的,这就是为什么我添加了关于将数据库整数映射到序数的最后一段。当然,我当然同意,对于高度非线性的映射(或经常变化的映射),另一种方法可能更容易。
    【解决方案3】:

    你的枚举类应该有一个内置的查找映射作为静态变量。因此你的枚举类应该是这样的。

    public static enum Day {
        SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);
    
        public final int fId;
    
        private Day(int id) {
            this.fId = id;
        }
    
    
       private static final Map<Integer, Day > lookup
       = new HashMap<Integer, Day >();
    
       static {
       for (Day s : EnumSet.allOf(Day.class))
             lookup.put(s.getIntValue(), s);
       }
    
       public static Day getValue(int intValue) {
          return lookup.get(intValue);
       }
    
    }
    

    然后要根据 int i 检索正确的枚举,您可以调用

    Day.getValue(i);
    

    即使编号是非线性的或其中有间隙,这种方法也可以工作。

    【讨论】:

      【解决方案4】:

      已编辑 - 缓存创建延迟。

      您可以创建 Map&lt;Integer,Day&gt; 运行时并在 getDay 实现中使用它。

      public static enum Day {
          SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);
      
          private static Map<Integer,Day> CACHE = null;
      
          private static void lazyFillCache() {
              if (CACHE != null) return;
      
              final Map<Integer,Day> c = new HashMap<Integer,Day>();
              for (final Day d : Day.values()) {
                  c.put(d.fId, d);
              }
      
              CACHE = c;
          }
      
          public static Day getDay(int i) {
              lazyFillCache();
              return CACHE.get(i);
          }
      
          public final int fId;
      
          private Day(int id) {
              this.fId = id;
          }
      }
      

      编辑 - 受 Tom Hawtins 评论 here 的启发,您也可以使用此实现,它利用了 Java 类加载功能:

      public static enum Day {
          SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);
      
          private static class Cache {
              private static Map<Integer,Day> CACHE = new HashMap<Integer,Day>();
      
              static {
                  for (final Day d : Day.values()) {
                      CACHE.put(d.fId, d);
                  }
              }
          }
      
          public static Day getDay(int i) {
              return Cache.CACHE.get(i);
          }
      
          public final int fId;
      
          private Day(int id) {
              this.fId = id;
          }
      }
      

      【讨论】:

      • 那行不通!运行类的静态初始化程序时,枚举不可用 - 尝试自己执行它。代码运行时 Day.values() 为空
      • 是的,我想它可能会发生,奇怪的是它在我的机器上工作。 Mybe 一些奇怪的编译器优化。然后我建议在 getDay 方法中初始化 CACHE lazy。
      • 看起来我之前的实现实际上是可能的,缓存填充发生的静态块必须位于其他所有内容的末尾:stackoverflow.com/questions/536449/…
      • 我更喜欢通过将缓存放入私有 ctor 来设置缓存。 private Day(int id) { this.fId = id; CACHE.put(id,this); }
      【解决方案5】:

      Day.values() 将返回枚举值的(从零开始的)数组。

      【讨论】:

        【解决方案6】:

        Day myDay = Day.values()[x] - x 是 int 值

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多