如何通过其属性获取枚举类型?

The*_*tsu 9 java enums

我写了一个枚举类,我想要按类型获取属性并获取type by属性,但似乎不可能.

public enum AreaCode {
    area1(7927),
    area2(7928),
    area3(7929);

    private final int ac;

    AreaCode(int ac) {
        this.ac = ac;
    }

    int areaCode(){
        return ac;
    }

    AreaCode area(int n) {
        switch (n) {
            case 7927: return AreaCode.area1;
            case 7928: return AreaCode.area2;
            case 7929: return AreaCode.area3;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码不会编译.如何area(int n)上班?

Joa*_*uer 31

除了其他海报所指出的问题外,我会重写方法以避免重复信息(保持干燥!):

public static AreaCode area(int n) {
  for (AreaCode c : values()) {
    if (c.ac == n) {
      return c;
    }
  }
  // either throw the IAE or return null, your choice.
  throw new IllegalArgumentException(String.valueOf(n));
}
Run Code Online (Sandbox Code Playgroud)

  • 工作,但如果有大量的区号,这将变得效率低下.地图似乎更好. (3认同)
  • @G_H:这种低效**极**不可能对应用程序的整体性能产生任何影响,除非您确实拥有数千个区号(即使如此,您也可能不会注意到它)。如果*那*是这种情况,那么您可能一开始就不应该为此使用`enum`。 (2认同)
  • 关于不使用枚举来表示该数量的区号.尽管如此,Map是一种可以限制代码量的干净解决方案,它可以让以后更容易地转移到常规类.应避免过早优化,但在我看来,为问题选择最合适的数据结构还为时过早. (2认同)
  • 如果“area()”函数只占应用程序总执行时间的一小部分(这是最有可能的),那么将该函数优化为哈希映射不太可能提高现实世界的应用程序性能,即使该函数是一个订单速度更快。*“...Map 是一个限制代码量的干净解决方案”*这一主张并没有考虑到任何优化的给予和接受性质。也就是说,在这种情况下,您正在用执行时间换取更长的初始化时间和更大的内存占用(在特定环境中很重要)。 (2认同)

Mr.*_*irl 15

正如他们所说,有一种方法可以给猫皮肤.首先,枚举值应该是大写的(由下划线分隔的单词),因为它们是常量值,并且应该通过Java命名约定来对待它们.至少,它们应该以大写字母开头,因为所有类名都应该.

public enum AreaCode {
    AREA_1(7927),
    AREA_2(7928),
    AREA_3(7929);

    private int areaCode;

    private AreaCode(int areaCode) {
        this.areaCode = areaCode;
    }

    public int getAreaCode() {
        return areaCode;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,有三种方法可以通过实例变量检索枚举.switch语句,具有相等条件的循环和查找映射.最后一个场景可能会为您的程序添加更多内存,但如果您需要快速查找大量枚举,这将有助于您以恒定的速率O(1)时间执行此操作.

下面的每个枚举类都是相同的,但每个类都在内部做了不同的事情.通过将以下main()方法添加到这些类中的任何一个,您将获得相同的结果.

public static void main(String[] args) {
    System.out.println(retrieveByAreaCode(7928));
}
Run Code Online (Sandbox Code Playgroud)

上面的例子将打印:

AreaCode[name="AREA_2", value="7928"]
Run Code Online (Sandbox Code Playgroud)

开关

查找是O(1)(常数时间),但您需要对每个案例进行硬编码(不是非常动态).

public enum AreaCode {
    AREA_1(7927),
    AREA_2(7928),
    AREA_3(7929);

    private int areaCode;

    private AreaCode(int areaCode) {
        this.areaCode = areaCode;
    }

    public int getAreaCode() {
        return areaCode;
    }

    public static AreaCode retrieveByAreaCode(int n) {
        switch (n) {
            case 7927:
                return AreaCode.AREA_1;
            case 7928:
                return AreaCode.AREA_2;
            case 7929:
                return AreaCode.AREA_3;
            default:
                return null;
        }
    }

    @Override
    public String toString() {
        return String.format("%s[name=\"%s\", value=\"%d\"]",
                this.getClass().getName(), this.name(), this.getAreaCode());
    }
}
Run Code Online (Sandbox Code Playgroud)

查找是O(n)(线性时间),因此您需要遍历每个值,直到找到匹配项,但您确实需要对每个案例进行硬编码(动态).

public enum AreaCode {
    AREA_1(7927),
    AREA_2(7928),
    AREA_3(7929);

    private int areaCode;

    private AreaCode(int areaCode) {
        this.areaCode = areaCode;
    }

    public int getAreaCode() {
        return areaCode;
    }

    public static AreaCode retrieveByAreaCode(int n) {
        for (AreaCode areaCode : AreaCode.values()) {
            if (areaCode.getAreaCode() == n) {
                return areaCode;
            }
        }

        return null;
    }

    @Override
    public String toString() {
        return String.format("%s[name=\"%s\", value=\"%d\"]",
                this.getClass().getName(), this.name(), this.getAreaCode());
    }
}
Run Code Online (Sandbox Code Playgroud)

抬头

查找是O(1)(常量时间),您不需要对每个值进行硬编码(动态),但您需要存储占用内存的映射.

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

public enum AreaCode {
    AREA_1(7927),
    AREA_2(7928),
    AREA_3(7929);

    private static final Map<Integer, AreaCode> LOOKUP_MAP;
    private int areaCode;

    static {
        LOOKUP_MAP = new HashMap<Integer, AreaCode>();
        for (AreaCode areaCode : AreaCode.values()) {
            LOOKUP_MAP.put(areaCode.getAreaCode(), areaCode);
        }
        LOOKUP_MAP = Collections.unmodifiableMap(LOOKUP_MAP);
    }

    private AreaCode(int areaCode) {
        this.areaCode = areaCode;
    }

    public int getAreaCode() {
        return areaCode;
    }

    public static AreaCode retrieveByAreaCode(int n) {
        return LOOKUP_MAP.get(n);
    }

    @Override
    public String toString() {
        return String.format("%s[name=\"%s\", value=\"%d\"]",
                this.getClass().getName(), this.name(), this.getAreaCode());
    }
}
Run Code Online (Sandbox Code Playgroud)

通用方法

EnumUtils.java

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

public class EnumUtils {
    public static interface EnumProperty<T extends Enum<T>, U> {
        U getValue(T type);
    }

    public static <T extends Enum<T>, U> Map<U, T> createLookup(Class<T> enumTypeClass, EnumProperty<T, U> prop) {
        Map<U, T> lookup = new HashMap<U, T>();

        for (T type : enumTypeClass.getEnumConstants()) {
            lookup.put(prop.getValue(type), type);
        }

        return Collections.unmodifiableMap(lookup);
    }
}
Run Code Online (Sandbox Code Playgroud)
import java.util.Map;

public enum AreaCode {
    AREA_1(7927),
    AREA_2(7928),
    AREA_3(7929);

    private static final EnumUtils.EnumProperty<AreaCode, Integer> ENUM_PROP;
    private static final Map<Integer, AreaCode> LOOKUP_MAP;

    static {
        ENUM_PROP = new EnumUtils.EnumProperty<AreaCode, Integer>() {
            @Override
            public Integer getValue(AreaCode code) {
                return code.getAreaCode();
            }
        };
        LOOKUP_MAP = EnumUtils.createLookup(AreaCode.class, ENUM_PROP);
    }

    private int areaCode;

    private AreaCode(int areaCode) {
        this.areaCode = areaCode;
    }

    public int getAreaCode() {
        return areaCode;
    }

    public static AreaCode retrieveByAreaCode(int n) {
        return LOOKUP_MAP.get(n);
    }

    @Override
    public String toString() {
        return String.format("%s[name=\"%s\", value=\"%d\"]",
                this.getClass().getName(), this.name(), this.getAreaCode());
    }
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*rdt 12

您需要做的就是添加一个默认大小写,以便该方法始终返回一些异常或抛出异常:

AreaCode area(int n){
    switch (n) {
    case 7927: return AreaCode.area1;
    case 7928: return AreaCode.area2;
    case 7929: return AreaCode.area3;
    default: return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

或者更好

AreaCode area(int n){
    switch (n) {
    case 7927: return AreaCode.area1;
    case 7928: return AreaCode.area2;
    case 7929: return AreaCode.area3;
    default: throw new IllegalArgumentException(String.valueOf(n));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案的主要问题是它不够健壮,并且存在潜在的维护问题。每次添加新的枚举常量时,都需要编辑 switch-case 块。@Joachim Sauer 发布的解决方案的优点是它对任意数量的枚举常量都有效,即使枚举随时间演变。 (2认同)