java enum int 转换为枚举_关于java:从枚举序号转换为枚举类型

我有一个枚举类型ReportTypeEnum,它在所有类的方法之间传递,但是我需要在URL上传递它,所以我使用序数方法来获取int值。在我把它放到我的另一个JSP页面之后,我需要将它转换回一个ReportTypeEnum,以便继续传递它。

如何将序数转换为ReportTypeEnum?

使用Java 6 SE。

没有Java 6 ee,直到现在(AFAIK)。Java se 6,Java ee 5.

我的爪哇

要将序数转换为其枚举重新表示,您可能需要执行以下操作:

ReportTypeEnum value = ReportTypeEnum.values()[ordinal];

请注意数组边界。

请注意,对values()的每次调用都会返回一个新克隆的数组,这可能会以负面的方式影响性能。如果经常调用数组,您可能需要缓存它。

关于如何缓存values()的代码示例。

编辑此答案以包括评论中给出的反馈

例如stackoverflow.com/a/19277247

我实现了这个解决方案,但它对我不起作用。它返回的顺序值不保证与枚举类型的添加顺序匹配。我不知道这正是这个答案所提倡的,但我还是想警告人们

@icesdante:序数肯定与源中枚举值的顺序相对应。如果你观察到一种不同的行为,那么肯定是有别的问题。然而,由于其他答案中列出的所有原因,我的上述答案都不理想。

这几乎肯定是个坏主意。当然,如果序数事实上是持久的(例如,因为有人在URL上加了书签),这意味着您以后必须始终保留enum的顺序,这对于代码维护人员来说可能并不明显。

为什么不使用myEnumValue.name()编码enum(并通过ReportTypeEnum.valueOf(s)解码)?

更好的主意

我同意,这是更好的解决方案。

如果更改枚举的名称(但保留排序),会怎么样?

@阿恩-我认为这比一些没有经验的人来在开头或正确的字母/逻辑位置添加value的可能性要小得多。(逻辑的意思是,例如,TimeUnit值具有逻辑位置)

我当然更喜欢强制枚举顺序而不是枚举的名称……这就是为什么我更喜欢在数据库中存储序号而不是枚举的名称。此外,最好使用int操作而不是字符串…

我同意。在公共API中,更改枚举的名称会破坏向后兼容性,但更改顺序不会。因此,使用名称作为"密钥"更为合理。

对于值比应用程序寿命长的情况,这是一个很好的警告。通过将枚举的序号写入文件或数据库,可以(可能是在不知情的情况下)假定枚举值的顺序永远不会更改。但在很多情况下,枚举值只在程序执行期间使用。所以明智地选择,考虑约阿希姆·绍尔的回答。它实际上回答了手头的问题。;)

存储序数可以更容易地将您的想法翻译成其他语言。如果您需要用C编写一些组件呢?

让我们不要从一个简短的问题中猜测OP的持久性需求。也许这个值在有线格式中的停留时间不会超过一个用户会话。或者可能是。

我强烈反对。枚举类型是为了顺序而引入的,例如在pascal中,这样每个枚举值都可以相互比较。

在Android上,如果您存储枚举名并使用proguard,那么您需要确保proguard不会混淆枚举名。

如果我要经常使用values():

enum Suit {

Hearts, Diamonds, Spades, Clubs;

public static final Suit values[] = values();

}

同时where.java:

Suit suit = Suit.values[ordinal];

注意阵列边界。

+1这是迄今为止最好的解决方案imho,因为可以传递顺序,特别是在android.os.message中。

这是非常令人担忧的,因为数组是可变的。尽管值[]是最终值,但它不会阻止代码中的某个地方出现Suit.values[0] = Suit.Diamonds;。理想情况下,这永远不会发生,但不暴露可变字段的总体原则仍然适用。对于这种方法,考虑使用Collections.unmodifiableList或类似的方法。

-private static final suit values[]=values();public static suit[]getvalues()返回值;

@pratyush使数组变量不可变,但不改变其内容。我仍然可以做getValues()[0]=somethinglese;

我同意大多数人的看法,使用序数可能是一个坏主意。我通常通过给枚举一个私有的构造函数来解决这个问题,该构造函数可以例如一个db值,然后创建一个与jan答案中的函数类似的静态fromDbValue函数。

public ReportTypeEnum {

R1(1),

R2(2),

R3(3),

R4(4),

R5(5),

R6(6),

R7(7),

R8(8);

private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);

private static Map lookup;

private Integer dbValue;

private ReportTypeEnum(Integer dbValue) {

this.dbValue = dbValue;

}

static {

try {

ReportTypeEnum[] vals = ReportTypeEnum.values();

lookup = new HashMap(vals.length);

for (ReportTypeEnum  rpt: vals)

lookup.put(rpt.getDbValue(), rpt);

}

catch (Exception e) {

// Careful, if any exception is thrown out of a static block, the class

// won't be initialized

log.error("Unexpected exception initializing" + ReportTypeEnum.class, e);

}

}

public static ReportTypeEnum fromDbValue(Integer dbValue) {

return lookup.get(dbValue);

}

public Integer getDbValue() {

return this.dbValue;

}

}

现在,您可以在不更改查找的情况下更改顺序,反之亦然。

这是正确的答案。与其他更直接但可能无效的答案相比(由于未来代码的变化),它得到的分数如此之少,我很惊讶。

您可以使用静态查阅表格:

public enum Suit {

spades, hearts, diamonds, clubs;

private static final Map lookup = new HashMap();

static{

int ordinal = 0;

for (Suit suit : EnumSet.allOf(Suit.class)) {

lookup.put(ordinal, suit);

ordinal+= 1;

}

}

public Suit fromOrdinal(int ordinal) {

return lookup.get(ordinal);

}

}

也见枚举。

真的!哇!当然,这很干净,但是…你知道-我内心的C程序员痛苦地尖叫着,因为你分配了一个完整的哈希图,并在里面执行查找,所有这些都只是为了基本上管理4个常量:黑桃、红心、钻石和梅花!C程序员将为每个字符分配1个字节:"const char clubs=0;"等…是的,hashmap查找是o(1),但是hashmap的内存和CPU开销,在这种情况下,使它比直接调用.values()慢很多个数量级,而且资源消耗也很大!难怪如果人们这样写的话,Java就是一个记忆之王…

不是每个节目都需要一场三人A的比赛。在许多情况下,将内存和CPU用于类型安全、可读性、可维护性、跨平台支持、垃圾收集等方面。是合理的。更高层次的语言存在是有原因的。

但是,如果您的密钥范围始终是0...(n-1),那么数组的代码更少,可读性也更高;性能提升只是一个额外的好处。private static final Suit[] VALUES = values();和public Suit fromOrdinal(int ordinal) { return VALUES[ordinal]; }。额外的优点:在无效的序号上立即崩溃,而不是静默返回空值。(并非总是优势。但通常情况下)

这是我用的。我并没有假装它远不如上述简单的解决方案"高效"。它所做的是提供比"arrayindexoutofbounds"更清晰的异常消息,因为在上面的解决方案中使用了无效的序号。

它利用了这样一个事实:Enumset JavaDoc以自然顺序指定迭代器返回元素。如果这不正确,就有断言。

JUnit4测试演示了如何使用它。

/**

* convert ordinal to Enum

* @param clzz may not be null

* @param ordinal

* @return e with e.ordinal( ) == ordinal

* @throws IllegalArgumentException if ordinal out of range

*/

public static > E lookupEnum(Class clzz, int ordinal) {

EnumSet set = EnumSet.allOf(clzz);

if (ordinal < set.size()) {

Iterator iter = set.iterator();

for (int i = 0; i < ordinal; i++) {

iter.next();

}

E rval = iter.next();

assert(rval.ordinal() == ordinal);

return rval;

}

throw new IllegalArgumentException("Invalid value" + ordinal +" for" + clzz.getName( ) +", must be

}

@Test

public void lookupTest( ) {

java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);

System.out.println(tu);

}

这就是我用Proguard在Android上所做的:

public enum SomeStatus {

UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order

private static SomeStatus[] values = null;

public static SomeStatus fromInteger(int i) {

if(SomeStatus.values == null) {

SomeStatus.values = SomeStatus.values();

}

if (i < 0) return SomeStatus.values[0];

if (i >= SomeStatus.values.length) return SomeStatus.values[0];

return SomeStatus.values[i];

}

}

它很短,我不需要担心Proguard中出现异常

您可以定义一个简单的方法,例如:

public enum Alphabet{

A,B,C,D;

public static Alphabet get(int index){

return Alphabet.values()[index];

}

}

使用方法如下:

System.out.println(Alphabet.get(2));

所以有一种方法是doExampleEnum valueOfOrdinal = ExampleEnum.values()[ordinal];,它工作起来很容易,但是,如前所述,ExampleEnum.values()为每个调用返回一个新的克隆数组。那可能是不必要的昂贵。我们可以通过缓存类似于ExampleEnum[] values = values()的数组来解决这个问题。允许修改缓存数组也是"危险的"。有人可以编写ExampleEnum.values[0] = ExampleEnum.type2;,这样我就可以使用不做额外复制的访问器方法将其私有化。

private enum ExampleEnum{

type0, type1, type2, type3;

private static final ExampleEnum[] values = values();

public static ExampleEnum value(int ord) {

return values[ord];

}

}

您可以使用ExampleEnum.value(ordinal)来获取与ordinal关联的枚举值。

public enum Suit implements java.io.Serializable, Comparable{

spades, hearts, diamonds, clubs;

private static final Suit [] lookup  = Suit.values();

public Suit fromOrdinal(int ordinal) {

if(ordinal< 1 || ordinal> 3) return null;

return lookup[value-1];

}

}

测试类

public class MainTest {

public static void main(String[] args) {

Suit d3 = Suit.diamonds;

Suit d3Test = Suit.fromOrdinal(2);

if(d3.equals(d3Test)){

System.out.println("Susses");

}else System.out.println("Fails");

}

}

我很感谢您与我们分享,如果您有一个更有效的代码,我的枚举是巨大的,经常被调用数千次。

每个枚举都有name(),它给出一个具有枚举成员名称的字符串。

鉴于enum Suit{Heart, Spade, Club, Diamond},Suit.Heart.name()将给予Heart。

每个枚举都有一个valueOf()方法,它采用枚举类型和字符串来执行反向操作:

Enum.valueOf(Suit.class,"Heart")返回Suit.Heart。

为什么有人会使用序数,我无法理解。它可能快纳秒,但如果枚举成员发生变化,这是不安全的,因为另一个开发人员可能不知道某些代码依赖于序数值(特别是在问题中引用的JSP页面中,网络和数据库开销完全支配了时间,而不是在字符串上使用整数)。

因为比较整数比比较字符串快得多?

但如果有人修改枚举(添加/重新排序memvers),则序号将更改。有时,它是关于安全而不是速度的,特别是在JSP页面上,网络延迟是比较整数数组(字符串)和单个整数之间差异的1000000倍。

ToString可以被重写,因此它可能不会返回枚举名称。方法名()给出了枚举名(它是最终的)

代码注释和应用程序版本也是一回事(这样一来,文件格式可能更简单、更小)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值