java inner enum_关于java:通过其内部字段获取枚举

具有内部字段的枚举,类似于映射。

现在,我需要通过其内部字段获取枚举。

写下:

package test;

/**

* Test enum to test enum =)

*/

public enum TestEnum {

ONE(1), TWO(2), THREE(3);

private int number;

TestEnum(int number) {

this.number = number;

}

public TestEnum findByKey(int i) {

TestEnum[] testEnums = TestEnum.values();

for (TestEnum testEnum : testEnums) {

if (testEnum.number == i) {

return testEnum;

}

}

return null;

}

}

但是,每次我需要找到合适的实例时,通过所有枚举进行查找并不是很有效。

有没有其他方法可以做到这一点?

你能提供一些关于如何使用这个的更多的信息吗?

@卡尔,我认为这是一个很常见的模式,使用了很多不同的方式。

您的findbykey()方法应该是静态的-否则您必须使用枚举对象调用该方法,如testenum.one.findbykey()而不是testenum.findbykey()。

您可以将static Map与static初始值设定项一起使用,该初始值设定项使用由其number字段键控的TestEnum值填充它。

注意,findByKey已制成static,number也已制成final。

import java.util.*;

public enum TestEnum {

ONE(1), TWO(2), SIXTY_NINE(69);

private final int number;

TestEnum(int number) {

this.number = number;

}

private static final Map map;

static {

map = new HashMap();

for (TestEnum v : TestEnum.values()) {

map.put(v.number, v);

}

}

public static TestEnum findByKey(int i) {

return map.get(i);

}

public static void main(String[] args) {

System.out.println(TestEnum.findByKey(69)); // prints"SIXTY_NINE"

System.out.println(

TestEnum.values() == TestEnum.values()

); // prints"false"

}

}

您现在可以期望findByKey是O(1)操作。工具书类

JLS 8.7静态初始值设定项

JLS 8.9枚举

相关问题

Java中的静态引用程序

如何在爪哇初始化静态地图

关于values()的说明

main方法中的第二条println语句显示:values()在每次调用时都返回一个新分配的数组!最初的O(N)解决方案只需调用values()一次并缓存数组,就可以做得更好一些,但该解决方案平均仍为O(N)。

好的解决方案。这也是我想到的。我通常在static { ... }内填充地图。

为什么懒惰?最简单的方法是在静态块中初始化映射。

@彼得:增加了热切的版本。谢谢你的建议。我不太确定哪一种是比较常见的技术。

正如您所知道的,这个热切的版本在实践中无法工作(由于枚举是如何创建的)。实际上,您需要将该静态块嵌入到另一个嵌套的静态类中。

你发布的懒惰版本不是线程安全的。假设线程A和B都在map=null之前停止。A在返回前继续并停止。B执行map=并在初始化值之前停止。然后A继续,可以返回不正确的空值。尽管这不太可能,但对于多线程来说,代码仍然不正确。

@Mjessup:很好的评论!是的,我根本没有考虑并发性。那么渴望的版本呢?为什么@james说它在实践中不起作用?我将在下一次修订中解决所有这些问题。

枚举父类在实例化子类之前初始化。因此,值数组通常在主枚举类的静态块中无效。如果这个静态块在另一个类中,那么没有问题。

嗯,经过进一步的调查,我有点不舒服。我想这只是一个问题,如果您试图访问枚举构造函数中的静态映射。我的错,这应该是可行的。

R:"O(n)"。当n是一个可能变大的变量时,比较大操作系统是有用的。当n是枚举中常量的数目时,我确切知道有多少个常量,并且一个o(n^2)解决方案可能比其他人的o(logn)解决方案更好。

@凯文:是的,但由于这个问题实际上需要一张地图,所以我想提出一个不同的解决方案:ala EnumMap,我们可以有一个专门的IntMiniMap implements Map,它有get(int)过载(防止自动氧化),并在屏幕后面进行线性搜索(或者根据n的阈值对排序的数组进行二进制搜索)。对于映射的线性搜索是很难看的,但是如果出于性能原因而必须这样做,那么至少要将其隐藏在一个专门的Map中,而不是强迫人们咬自己的舌头,然后在各处进行搜索。思想?

太棒了,但太可怕了,太可怕了,太可怕了!!!!(但不是你的错…):D+1

69是怎么出现的?

尽管有人建议使用Map,但还是要三思。

您最初的解决方案,特别是对于小的枚举,可能比使用哈希图更快。

在枚举包含至少30到40个元素之前,hashmap可能不会更快。

这是一个"如果它不坏,就不要修理它"的例子。

你凭什么认为江户十一〔十〕这么慢?它初始化一次,然后会比调用values()快得多(每次都必须是新分配的数组;尝试它TestEnum.values() == TestEnum.values()是false然后遍历每个元素。

@聚原润滑油:我做过一次经验测试。看看HashMap.get的实现。它所做的远远超过了OP最初的实现。不久前我做了这个精确的测试,发现在至少有30个元素要遍历之前,考虑哈希图是不值得的。也就是说,您的实现是完全正确的,并且将完成一项工作。

我认为30-40可能是一个夸大,但我会尝试基准这一点。不过,我认为这个答案在本质上是正确的,对于这个数字的某些选择,需要指出。

我已经使用枚举中的10个常量完成了一个粗略的第一个基准测试。对于小的int值,我的MacBook上的性能是可比的——hashmap性能只比线性搜索差10%。使用随机的、较大的整数作为值,映射性能会变得更差,因为每个查询都需要分配一个整数实例。我在计时循环中测试了10个成功的查询和2个未找到的查询。这离最终的答案还很远,但至少应该说明亚历山大的答案并不是离题太远。我会在有机会的时候完成并发布基准代码。

哦!当然,在我的基准测试中,findbykey方法不调用values()。values()缓存在私有静态字段中。令人遗憾的是,values()被强制在每次调用时创建和填充一个全新的数组,因为它被声明为返回数组而不是集合类型。

一个解决方案是添加

public final Test[] TESTS = { null, ONE, TWO, THREE };

public static Test getByNumber(int i) {

return TESTS[i];

}

到枚举。

如果内部数据不是整数,则可以在static { ... }初始值设定项中填充映射。该图稍后可用于上述getByNumber方法中。

您应该有一个哈希映射,其中数字作为键,枚举值作为值。

此映射通常可以在您的存储库中。然后,您可以用首选的枚举值轻松地替换数据库中的int变量。

如果您的键(int值)存储在数据库中,那么在您的业务层的枚举中携带这些键是一种糟糕的设计。如果是这种情况,我建议不要在枚举中存储int值。

你能详细解释一下吗?对我来说,在Java端使用EDCOX1 0表示在数据库级别上用EDCOX1 OR 1表示的枚举是很自然的。为什么使用enum是一个糟糕的设计?你建议哪种选择?

@帕斯卡:在分层应用程序中,您的服务代码不应该知道数据库中的键值。这不是层之间的松散耦合。如果您正在更改数据库或将其替换为某种类型的DataGrid(例如云解决方案),该怎么办?那么枚举中的数据库键就没有任何意义了。但是,如果您在集成逻辑中使用枚举,那么我会说PolyGene润滑剂Post是一个很好的解决方案。

如果密钥是业务密钥,而不仅仅是主键/外键,那么即使在服务层上使用,我也会投票支持PolyGene润滑剂解决方案。

谢谢。但是,如果您在持久层级别使用int,而在业务层级别使用enum,我仍然看不到问题。我看不出与携带钥匙的业务对象有什么区别。

如果您在枚举中携带了一个int值,而该值在将来的DataGrid解决方案中没有使用,或者如果您更改了数据库,而int值是错误的,那么您最多拥有一个难以读取的应用程序。您还可能面临这样的风险:有人对int值而不是枚举进行编码,因为它是可用的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值