【问题标题】:How to convert string result of enum with overridden toString() back to enum?如何将覆盖 toString() 的枚举字符串结果转换回枚举?
【发布时间】:2010-09-19 09:37:10
【问题描述】:

给定以下 java 枚举:

public enum AgeRange {

   A18TO23 {
        public String toString() {        
            return "18 - 23";
        }
    },
   A24TO29 {
        public String toString() {        
            return "24 - 29";
        }
    },
   A30TO35 {
        public String toString() {        
            return "30 - 35";
        }
    },

}

有没有办法将字符串值“18 - 23”转换为相应的枚举值,即 AgeRange.A18TO23 ?

谢谢!

【问题讨论】:

    标签: java enums enumeration converter


    【解决方案1】:

    最好和最简单的方法是这样的:

    public enum AgeRange {
        A18TO23 ("18-23"),
        A24TO29 ("24-29"),
        A30TO35("30-35");
    
        private String value;
    
        AgeRange(String value){
            this.value = value;
        }
    
        public String toString(){
            return value;
        }
    
        public static AgeRange getByValue(String value){
            for (final AgeRange element : EnumSet.allOf(AgeRange.class)) {
                if (element.toString().equals(value)) {
                    return element;
                }
            }
            return null;
        }
    }
    

    然后你只需要调用 getByValue() 方法并在其中输入 String

    【讨论】:

    • 我同意将值放入构造函数中很好。对于非常大的枚举(它们确实必须非常大),使用地图是有意义的。我个人也会从循环内部返回,但我从来都不喜欢“从一个地方返回,不管可读性如何”:)
    • 另外一点 - 最好使用 EnumSet.allOf 而不是 AgeRange.values() 否则你会为每次调用创建一个新数组。
    • 非常有趣。代码中发生的很多事情对我来说都是新的。感谢您的提示!
    • 代替你的方法getByValue(String),你不应该直接委托给枚举固有的valueOf(String)吗?参考:stackoverflow.com/questions/11914792/…
    【解决方案2】:

    你总是可以创建一个从字符串到值的映射——静态地这样做,所以你只需要映射一次,假设返回的字符串随着时间的推移保持不变。据我所知,没有任何内置功能。

    【讨论】:

    • 这是一种更好的处理方式。然后在枚举时创建映射,并且比迭代数组快得多。
    • 我也在考虑这种方法,但我在这个枚举中只有大约 15 个值。创建地图是否更高效?
    • 说实话,可能不会。哈希表非常适合处理大量数据,但我怀疑比较 15 个值(在最坏的情况下)将与获取哈希码、找到正确的存储桶等一样快。
    【解决方案3】:

    根据有效java(2nd ed)第30条,可以(比循环快很多)

    public enum AgeRange {
           A18TO23("18-23"),
           A24TO29("24-29"),
           A30TO35("30-35");
    
           private final String value;
    
           AgeRange(String value){
              this.value = value;
           }
    
           @Override public String toString(){
               return value;
           }
    
           private static final Map<String, AgeRange> stringToEnum =
               new HashMap<String, AgeRange>();
    
           static {
               for (AgeRange r : values()) {
                   stringToEnum.put(r.toString(), r);
               }
           }
    
           public static AgeRange getByValue(String value){
               return stringToEnum.get(value);
           }
    }
    

    【讨论】:

      【解决方案4】:
      for (AgeRange ar: EnumSet.allOf(AgeRange)) {
          if (ar.toString().equals(inString)) {
               myAnswer = ar;
               break;
          }
      }
      

      或者类似的东西?刚刚输入,还没有通过编译器运行。原谅(评论)错别字...

      或者使用这样的逻辑来构建一次地图。避免在运行时迭代。好主意,乔恩。

      【讨论】:

        【解决方案5】:

        该类覆盖“toString()” - 因此,要获得反向操作,您需要覆盖 valueOf() 以将 toString() 的输出转换回 Enum 值。

        public enum AgeRange {
        
           A18TO23 {
                public String toString() {        
                        return "18 - 23";
                }
                public AgeRange valueOf (Class enumClass, String name) {
                        return A18T023
                }
            },
        
            .
            .
            .
        }
        

        买家当心 - 未经编译和未经测试...

        toString()valueOf() 的机制是 API 的记录部分

        【讨论】:

        • 第二个应该是 valueOf 方法吗?
        • -1 如果我没记错的话,这里对 valueOf 的建议是……错误,要温柔 ;-)。 valueOf() 是静态的,在特定枚举值的主体中没有用处。即使所有这些都修复了,“正确”的实现也是错误的,因为编译器不允许在static public valueOf(String) 上进行静态覆盖。常见的解决方法是干脆不使用valueOf - 使用不同的名称。
        【解决方案6】:

        您可以尝试以下方法吗?

        static AgeRange fromString(String range) {
            for (AgeRange ageRange : values()) {
                if (range.equals(ageRange.toString())) {
                    return ageRange;
                }
            }
            return null;   
        }
        

        或者,正如其他人建议的那样,使用缓存方法:

        private static Map<String, AgeRange> map;
        
        private static synchronized void registerAgeRange(AgeRange ageRange) {
            if (map == null) {
                map = new HashMap<String, AgeRange>();
            }
            map.put(ageRange.toString(), ageRange);
        }
        
        AgeRange() {
            registerAgeRange(this);
        }
        
        static AgeRange fromString(String range) {
            return map.get(range);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-21
          • 2016-07-30
          • 2010-10-03
          相关资源
          最近更新 更多