枚举项的数量限制在64个以内
为了更好的使用枚举,Java提供了两个枚举集合:EnumSet和EnumMap,这两个集合的使用方法都比较简单,EnumSet表示其元素必须是某一枚举的枚举项,EnumMap表示Key值必须是某一枚举的枚举项,由于枚举类型的实例数量固定并且有限,相对来说,EnumSet和EnumMap的效率会比其他Set和Map要高.
虽然EnumSret很好用,但是它有一个隐藏的特点.项目中可能定义非常多的枚举项,然后通过EnumSet访问,遍历,但它对不同的枚举数量有不同的处理方式.为了进行对比,我们定义两个枚举,一个数量等于64,一个是65(大于64即可,为什么是64而不是128,512呢?)代码如下:
1 import java.util.EnumSet; 2 3 4 public class Client { 5 public static void main(String[] args) { 6 //创建生成包含所有枚举项的EnumSet 7 EnumSet<Const> cs = EnumSet.allOf(Const.class); 8 EnumSet<LargeConst> lcs = EnumSet.allOf(LargeConst.class); 9 //打印出枚举项数量 10 System.out.println("Const枚举项数量:" + cs.size()); 11 System.out.println("LargeConst枚举项数量:" + lcs.size()); 12 //输出两个EnumSet的class 13 System.out.println(cs.getClass()); 14 System.out.println(lcs.getClass()); 15 } 16 } 17 18 //普通枚举项,数量小于64 19 enum Const { 20 A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, BA, CA, DA, EA, FA, GA, HA, NA, OA, PA, QA, RA, SA, TA, UA, VA, WA, XA, YA, ZA, BC, CC, DC, EC, FC, GC, HC, IC, JC, KC, LC, MC, NC, OC, PC, QC, RC; 21 } 22 //大枚举,数量超过64 23 enum LargeConst { 24 A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, BA, CA, DA, EA, FA, GA, HA, IA, JA, KA, LA, MA, NA, OA, PA, QA, RA, SA, TA, UA, VA, WA, XA, YA, ZA, AB, BB, CB, DB, EB, FB, GB, HB, IB, JB, KB, LB, MB; 25 }
Const中的枚举项数量是64,LargeConst的数量是65,上面的代码让他们转换成EnumSet,然后判断一下它们的class类型是否相同.
运行结果:
Const枚举项数量:64 LargeConst枚举项数量:65 class java.util.RegularEnumSet class java.util.JumboEnumSet
很遗憾,两者不相等,就差1个元素,两者就不相同了,这也是我们要重点关注枚举项数量的原因,通过源码看Java是如何处理的?首先跟踪allOf方法,其源代码如下:
1 /** 2 * Creates an enum set containing all of the elements in the specified 3 * element type. 4 * 5 * @param elementType the class object of the element type for this enum 6 * set 7 * @throws NullPointerException if <tt>elementType</tt> is null 8 */ 9 public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) { 10 EnumSet<E> result = noneOf(elementType);//生成一个空的EnumSet 11 result.addAll();..加入所有的枚举项 12 return result; 13 }
allOff通过noneOf方法首先生成一个EnumSet对象,然后把所有的枚举项都加进去,问题可能就出现在EnumSet的生成上了.查看noneOf的代码.
1 /** 2 * Creates an empty enum set with the specified element type. 3 * 4 * @param elementType the class object of the element type for this enum 5 * set 6 * @throws NullPointerException if <tt>elementType</tt> is null 7 */ 8 public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) { 9 Enum[] universe = getUniverse(elementType); 10 if (universe == null) 11 throw new ClassCastException(elementType + " not an enum"); 12 13 if (universe.length <= 64) //枚举数量小于64 14 return new RegularEnumSet<>(elementType, universe); 15 else //枚举数量大于64 16 return new JumboEnumSet<>(elementType, universe); 17 }
当枚举数量小于64的时候,创建一个RegularEnumSet实例对象,大于64时则创建一个JumboEnumSet实例对象.
为什么要这么处理?这还要看着两个类之间的差异.
RegularEnumSet类,代码如下:
1 class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> { 2 private long elements = 0L;//记录所有枚举排序号,注意是long型 3 RegularEnumSet(Class<E>elementType, Enum[] universe) {//构造函数 4 super(elementType, universe); 5 } 6 void addAll() {//加入所有元素 7 if (universe.length != 0) 8 elements = -1L >>> -universe.length; 9 } 10 }
枚举项的排序值ordinal是从0,1,2,......依次递增的,没有重号,没有跳号,RegularEnumSet就是利用这一点把每个枚举项的ordinal映射到一个long类型的每个位上的,
注意看addAll方法的elements元素,它使用了无符号右移操作,符号位为0,并补充地位,简单的说,Java把一个不多于64个枚举项的枚举映射到了一个long类型变量上,这才是EnumSet处理的重点,其他的size方法,constains方法都是根据elements计算出来的,
一个long类型的数字包含了所有的枚举项,其效率和性能肯定都是非常优秀的.
long类型是64位的,所以RegularEnumSet类型也就只能负责枚举项数量,不大于64的枚举,大于64则由JumboEnumSet处理,看其源代码:
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {private long elements[];//映射所有的枚举项JumboEnumSet(Class<E>elementType, Enum[] universe) {//构造函数super(elementType, universe);elements = new long[(universe.length + 63) >>> 6];//默认长度是枚举项数量除以64再加1 }void addAll() {//elements中每个元素表示64个枚举项for (int i = 0; i < elements.length; i++)elements[i] = -1;elements[elements.length - 1] >>>= -universe.length;size = universe.length;} }
JumboEnumSet类把枚举项按照64个元素一组拆分了多组,每组都映射到一个long类型的数字上,然后该数组再放置到elements数组中,简单来说JumboEnumSet类的原理与RegularEnumset相似,只是JumboEnumSet使用了long数组能容纳更多的枚举项.
在我们的开发中很少用到位操作.RegularEnumSet是把每个枚举项编码映射到了一个long类型数字的每个位上.JumboEnumSet是先按照64个一组进行拆分,然后每个组再映射到一个long类型数字的每个位上.从这里可以看出数字编码的奥秘.
EnumSet提供的两个实现都是基本的数字类型操作,其性能肯定比其他的Set类型要好很多,特别是Enum的数量少于64的时候.简直非一般的速度.
本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5639983.html,如需转载请自行联系原作者
枚举项的数量限制在64个以内相关推荐
- [改善Java代码]枚举项的数量限制在64个以内
为了更好的使用枚举,Java提供了两个枚举集合:EnumSet和EnumMap,这两个集合的使用方法都比较简单,EnumSet表示其元素必须是某一枚举的枚举项,EnumMap表示Key值必须是某一枚举 ...
- 把数据库中有关枚举项值的数字字符串转换成文字字符串
原文:把数据库中有关枚举项值的数字字符串转换成文字字符串 标题可能无法表达我的本意.比如,有这样一个枚举: public enum MyChoice { MyFirstChoice = 0, MySe ...
- 学习笔记---取得枚举项的2种方法: Enum.GetValues()-Array.GetValue()和Enum.GetNames()-Enum.Parse()...
代码 namespace EnumDemo { public enum Color { red = 0, orange =1, yellow =2, green=4, blue =5, cyan =6 ...
- java根据enum某个属性值获取枚举项
现有如下枚举,假设需要找出status=3的枚举项 public enum StatusEnum {DRAFT(1, "草稿"),CHECKING(2, "审核中&quo ...
- 取枚举的参数c语言,求解:如何获得enum类型中枚举值的数量
评论 # re: 求解:如何获得enum类型中枚举值的数量 2009-11-11 20:43 OwnWaterloo # re: 求解:如何获得enum类型中枚举值的数量[未登录] 2009-11-1 ...
- Java--枚举类型(枚举类型介绍 定义枚举类型 枚举类型的使用 枚举类型的注意事项 遍历枚举项)
01: Java–枚举类型(枚举类型介绍 & 定义枚举类型 & 枚举类型的使用 & 枚举类型的注意事项 & 遍历枚举项) 02: Java–枚举类型(枚举类型实现接口 ...
- JAVA动态增加枚举项
前言 在项目中,会存在很多枚举,比如下面颜色和水果的枚举,COLOR[RED(1),GREEN(2),BLUE(3)],FRUIT[APPLE(4),BANANA(5),ORANGE(6)],但是问题 ...
- 64位以内Rabin-Miller 强伪素数测试和Pollard rho 因数分解解析
在求解POJ1811题Prime Test中应用到的两个重要算法是Rabin-Miller强伪素数测试和Pollard r因数分解算法.前者可以在的时间内以很高的成功概率判断一个整数是否是素数.后者可 ...
- php中 判断表中是否有重复,PHP:最常见的表中回显重复项的数量
我试图回应表中最常见的重复项.我已经能够回显重复项的名称,但我正在寻找的是表中的一个单独的列,显示重复发生的次数.有没有一种方法来回显COUNT(*)值?另外一种按大小组织值的方法会很有帮助. 我的P ...
最新文章
- sku属性组合小例子
- android.view.WindowManager$BadTokenException: Unable to add window — token null
- android rxbus 一个页面监听,Android RxBus的使用
- 我被男朋友整整欺骗了两年可结果却让我感动!
- 上传分片切片大文件 XLSX/CSV/TXT
- oracle数据库例题答案下载,Oracle数据库试题及答案[教学知识]
- 图解机器学习:人人都能懂的算法原理
- 猫怎么设置虚拟服务器,光纤猫设置虚拟服务器
- “磁碟机”病毒肆虐 数万电脑中招
- 广告是如何找到你的?
- Linux下C程序的编辑,编译和运行以及调试
- 第二届“中国制造(深圳)高峰论坛”举行
- 解剖学坐标体系(LPS , RAS和LAS)
- 力扣周赛337场 第一题6319.奇偶位数
- C语言-广度优先遍历
- EDU教育邮箱有这么多学生福利,你确定不搞一个?
- python模拟萌妹音让室友疯狂吃鸡
- Apple Push Notification Service(苹果推送服务)
- webstorm使用补丁包破解
- .NET 二维码生成
热门文章
- WordPress主题LensNews1.8模板源码,WP多功能新闻积分商城主题
- aba问题mysql_面试题总结:可能是全网最好的MySQL重要知识点
- 漂亮的个人团队介绍网页模板
- 盲盒拓客小程序商家联盟红包分销裂变抽奖小程序源码
- PHP未来码支付V1.3网站源码开源版
- [Fanly Submit V4.1]WordPress插件普通收录
- WebBrowser中显示乱码
- Linux Shell脚本入门教程系列之(六)Shell数组
- PHP数组缓存:三种方式JSON、序列化和var_export的比较
- jQuery倒计时(仿团购)