当前位置: 首页 > news >正文

黄冈工程建设标准造价信息网seo软件

黄冈工程建设标准造价信息网,seo软件,阿里巴巴国际站入驻费用,建设旅游网站财务分析枚举是什么#xff1f; 枚举就是将一个有限集合中的所有元素列举出来#xff0c;在java中使用可以使用enum关键字来声明一个枚举类。 为什么使用枚举#xff1f; 之前当用到一些常量时#xff0c;便临时声明一个#xff0c;这样使得代码看起来很乱#xff0c;这里一个…枚举是什么 枚举就是将一个有限集合中的所有元素列举出来在java中使用可以使用enum关键字来声明一个枚举类。 为什么使用枚举 之前当用到一些常量时便临时声明一个这样使得代码看起来很乱这里一个常量那里一个常量所以可以想着把一些具有关联性的常量封装到一个类中类中的每一个变量使用public static final来进行修饰这样虽然解决了问题但是不是很优雅而且还是有点麻烦这个时候便可以使用枚举直接使用enum关键字声明一个枚举类直接将常量在枚举类中声明即可不需显示使用任何修饰符修饰因为这些问题编译器帮我们做了使用枚举更加安全、方便、优雅。 怎么使用枚举 使用enum声明枚举类即可我感觉有两种使用枚举的方式一种是使用默认的方式声明的变量及是枚举值另一种是想用几个字段拼成一个字段作为枚举值这两种使用方式如下 //字面值及是枚举值 public enum EnumTest{Cancel,Waiting,Payed;}---------------------------------------------------------------------------//使用自定义的构造方法创建枚举类已达到多个字段拼接成一个字段作为枚举值 public enum EnumTest{Cancel(0,000),Waiting(1,111),Payed(4,444);private final String name;private final String msg;//在这里自定义一个构造方法即可注意一定要讲构造方法私有化private EnumTest(String name,String msg) {this.name name;this.msg msg;}//重写构造方法public String toString() {return this.name-this.msg;} }-----------------------------------------------------------------------------//使用枚举类型 public class Test{public static void main(String[] args) {//使用时会发现多出了values方法未自定义这个方法可以获取到枚举类型中所有的枚举值EnumTest[] values EnumTest.values();for (int i 0; i values.length; i) {System.out.println(values[i]);}//使用时会发现多出了valuesOf方法未自定义这个方法可以获取指定的枚举值EnumTest cancel EnumTest.valueOf(Cancel);System.out.println(cancel);//直接使用枚举值System.out.println(EnumTest.Cancel);} } 枚举类型的使用非常简单但是肯定会有很多疑惑接下来根据源码来解析一下枚举的实现原理。 枚举的实现原理 在枚举类上使用 CtrlT 可以看到自定义枚举类的体系架构它竟然是java.lang.Enum的子类但是声明时并没有继承这个Enum类这时复制java.lang.Enum到API中查看可以看到解释文档这么写“Enum是所有Java语言枚举类型的公共基类。 有关枚举的更多信息包括由编译器合成的隐式声明方法的描述请参见The Java™ Language Specification的第8.9节当使用枚举类型作为集合的类型或映射中的键的类型时可以使用专门且高效的set和map实现。”这里边有几个关键词公共基类、编译器合成的隐式声明方法、作为集合的类型。根据这几个词可以推断被enum修饰之后编译器会隐式的去让当前枚举类继承Enum类并且隐式的声明一些处理的方法。所以这里先看一下Enum类的源码分析 /*** Enum是所有Java语言枚举类型的公共基类更多关于枚举的信息,包括对编译器合成的隐式声明方法的描述,可以参见java语言标准文档. * * 在将枚举类型用作集合的类型或映射中的键的类型时,可以使用更高效的java.util.EnumSet和java.util.EnumMap*/ public abstract class EnumE extends EnumE implements ComparableE, Serializable {//枚举常量的名称, 正如枚举声明中声明的那样.应该使用toString方法而不是访问这个字段private final String name;//返回此枚举常量的名称与在其枚举声明中声明的名称完全相同。public final String name() {return name;}//枚举常数的序号(它在枚举声明中的位置其中初始常数的序号为0)。private final int ordinal;//返回此枚举常数的序号(其在枚举声明中的位置其中初始常数的序号为0)。public final int ordinal() {return ordinal;}//唯一的构造函数,外界不能调用此构造函数它由编译器在响应枚举类型声明时发出的代码使用。protected Enum(String name, int ordinal) {this.name name;this.ordinal ordinal;}//返回此枚举常量的名称public String toString() {return name;}//如果指定的对象等于枚举常量则返回true。public final boolean equals(Object other) {return thisother;}//返回此枚举常量的散列代码public final int hashCode() {return super.hashCode();}//抛出CloneNotSupportedException。这保证了枚举不会被克隆保证枚举类是单例的protected final Object clone() throws CloneNotSupportedException {throw new CloneNotSupportedException();}//将此枚举与指定的对象进行顺序比较public final int compareTo(E o) {Enum? other (Enum?)o;EnumE self this;if (self.getClass() ! other.getClass() // optimizationself.getDeclaringClass() ! other.getDeclaringClass())throw new ClassCastException();return self.ordinal - other.ordinal;}//返回与枚举常量的枚举类型对应的类对象。public final ClassE getDeclaringClass() {Class? clazz getClass();Class? zuper clazz.getSuperclass();return (zuper Enum.class) ? (ClassE)clazz : (ClassE)zuper;}//返回具有指定名称的指定枚举类型的枚举常量。隐式定义public static T extends EnumT T valueOf(ClassT enumType, String name) {T result enumType.enumConstantDirectory().get(name);if (result ! null)return result;if (name null)throw new NullPointerException(Name is null);throw new IllegalArgumentException( No enum constant enumType.getCanonicalName() . name);}//枚举类不能有finalize方法。protected final void finalize() { }//防止违约反序列化private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException {throw new InvalidObjectException(cant deserialize enum);}private void readObjectNoData() throws ObjectStreamException {throw new InvalidObjectException(cant deserialize enum);} }再看一下一个简单枚举类编译后的字节码解析枚举的实现原理在解析中解释了 //被enum修饰的代码会被编译成一个继承了Enum类的最终类所以被enum修饰的枚举类不可被继承也不可继承其他类 public final class com.czp.enumeration.EnumTest extends java.lang.Enumcom.czp.enumeration.EnumTest {//声明的枚举值会声明成EnumTest类型的变量public static final com.czp.enumeration.EnumTest Cancel;public static final com.czp.enumeration.EnumTest Waiting;public static final com.czp.enumeration.EnumTest Payed;//使用一个静态代码块进行声明的枚举值的赋值操作static {};Code://--------------------- 处理三个枚举值 ----------------------------////创建一个EnumTest对象并且其引用进栈0: new #1 // class com/czp/enumeration/EnumTest//复制栈顶数值并且复制值进栈 3: dup//将Cancel作为一个String类型值放在栈顶 4: ldc #14 // String Cancel //将0压入栈顶6: iconst_0 //使用Enum中的构造方法 Enum(String name, int ordinal) 创建一个对象nameCancelordinal07: invokespecial #15 // Method init:(Ljava/lang/String;I)V //将构造的对象赋给变量Cancel10: putstatic #19 // Field Cancel:Lcom/czp/enumeration/EnumTest; 13: new #1 // class com/czp/enumeration/EnumTest16: dup17: ldc #21 // String Waiting19: iconst_120: invokespecial #15 // Method init:(Ljava/lang/String;I)V23: putstatic #22 // Field Waiting:Lcom/czp/enumeration/EnumTest;26: new #1 // class com/czp/enumeration/EnumTest29: dup30: ldc #24 // String Payed32: iconst_233: invokespecial #15 // Method init:(Ljava/lang/String;I)V36: putstatic #25 // Field Payed:Lcom/czp/enumeration/EnumTest;//------------------- 创建数组将所有枚举值放入到数组中 ---------------------// 39: iconst_3// 相当于创建一个数组数组引用入栈长度为栈顶元素340: anewarray #1 // class com/czp/enumeration/EnumTest //复制栈顶数值并且复制值进栈 43: dup//int型常量值0入栈作为数组下标44: iconst_0//获取到Cancel45: getstatic #19 // Field Cancel:Lcom/czp/enumeration/EnumTest; // 依次取出栈顶元素根据类型进行数组赋值操作 48: aastore49: dup50: iconst_151: getstatic #22 // Field Waiting:Lcom/czp/enumeration/EnumTest;54: aastore55: dup56: iconst_257: getstatic #25 // Field Payed:Lcom/czp/enumeration/EnumTest;60: aastore//将构建的数组对象赋给VALUES61: putstatic #27 // Field ENUM$VALUES:[Lcom/czp/enumeration/EnumTest;64: return //返回值为空//创建一个values方法用于获取所有枚举值(大致操作就是新弄一个数组将上边VALUES中数据复制到新数组返回新数组)public static com.czp.enumeration.EnumTest[] values();Code://获取到静态域中数组VALUES0: getstatic #27 // Field ENUM$VALUES:[Lcom/czp/enumeration/EnumTest;3: dup4: astore_0 // 该指令的行为类似于astore指令index为0的情况。5: iconst_06: aload_0 // 当前frame的局部变量数组中下标为0的引用型局部变量进栈7: arraylength //栈顶的数组引用arrayref出栈该数组的长度进栈。8: dup9: istore_1 //将栈顶int型数值存入第一个局部变量10: anewarray #1 // class com/czp/enumeration/EnumTest13: dup14: astore_215: iconst_016: iload_1 //第二个int型局部变量进栈//调用静态方法17: invokestatic #35 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V20: aload_2 21: areturn //从方法中返回一个对象的引用//根据枚举值的字面值获取到对应的枚举元素public static com.czp.enumeration.EnumTest valueOf(java.lang.String);Code:0: ldc #1 // class com/czp/enumeration/EnumTest2: aload_03: invokestatic #43 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;//类型转换检查如果该检查未通过将会抛出ClassCastException异常6: checkcast #1 // class com/czp/enumeration/EnumTest9: areturn 可以看到枚举类型被编译器编译成一个同名的java类所以这里这可以看出枚举实质就是类这个类继承Enum类另外每一个枚举值都会被声明成一个当前类类型的变量默认使用Enum中的构造方法初始化这个变量并且编译器还自定义添加了几个方法用于操作枚举类。 有的时候想利用枚举类中的枚举值作为键然后存储键值对到Map中如何实现呢很简单使用HashMap集合泛型中键使用枚举类作为类型即可但是呢java为了追求更好的效果提供了EnumMap类来处理这类问题看一下EnumMap的使用和基本原理底层使用数组来记录元素的添加 public static void main(String[] args) {//使用EnumMap来处理枚举集合的问题EnumMapEnumTest, String enumMap new EnumMap(EnumTest.class);//正好每一个枚举值的类型是一个枚举类型所以直接用即可enumMap.put(EnumTest.Cancel, Cancel);enumMap.put(EnumTest.Waiting, Waiting);enumMap.put(EnumTest.Cancel, Cancel);SetEnumTest keySet enumMap.keySet();for (EnumTest enumTest : keySet) {System.out.println(enumMap.get(enumTest));} }---------------------------------------------------------------------//EnumMap实现的基本原理底层用的是一个数组来存储元素 // Map implementation for use with enum type keys. Enum maps are represented internally as arrays. // 一个用于处理枚举类型的Map集合底层的实现方式是用的数组 //这里只看一下EnumMap是如何存储键值对的 public class EnumMapK extends EnumK, V extends AbstractMapK, V implements java.io.Serializable, Cloneable {//集合键的枚举类型的类对象private final ClassK keyType;//键值对中所有值的数组private transient Object[] vals;//映射个数private transient int size 0;//判断key的类型是否正确private void typeCheck(K key) {Class? keyClass key.getClass();if (keyClass ! keyType keyClass.getSuperclass() ! keyType)throw new ClassCastException(keyClass ! keyType);}//判断value的值private Object maskNull(Object value) {return (value null ? NULL : value);}//添加元素//将枚举值对应的编号作为key,value是传入的值public V put(K key, V value) {typeCheck(key);//获取到当前key,也就是枚举值对应的编号int index key.ordinal();//将编号作为下标在vals中获取对应的值Object oldValue vals[index];//替换或者添加一个元素vals[index] maskNull(value);if (oldValue null)size;return unmaskNull(oldValue);}}还有一个单列集合EnumSet专门用于处理枚举类型的集合其使用和基本原理如下底层用一个long类型的值来标记哪个元素已经添加 public static void main(String[] args) {EnumSetEnumTest enumSet EnumSet.allOf(EnumTest.class);enumSet.add(EnumTest.Cancel);enumSet.add(EnumTest.Waiting);enumSet.add(EnumTest.Payed);for (EnumTest e : enumSet) {System.out.println(e);} }--------------------------------------------------------------public abstract class EnumSetE extends EnumE extends AbstractSetE implements Cloneable, java.io.Serializable {//类型final ClassE elementType;//枚举中所有元素final Enum?[] universe;//-------------------------------创建一个EnumSet实例-------------------------////创建一个空的集合public static E extends EnumE EnumSetE noneOf(ClassE elementType) {//可以看到实例化的是RegularEnumSet或者JumboEnumSet类的对象if (universe.length 64)return new RegularEnumSet(elementType, universe);elsereturn new JumboEnumSet(elementType, universe);}//使用指定的枚举类型创建一个集合public static E extends EnumE EnumSetE allOf(ClassE elementType) {EnumSetE result noneOf(elementType);result.addAll();return result;}//添加元素时调用的是子类中的方法因为EnumSet中没有添加的方法代码如下//说一下RegularEnumSet和JumboEnumSet(这部分代码是在别处贴过来的)//---------------RegularEnumSet实现代码---------------------//class RegularEnumSetE extends EnumE extends EnumSetE {//仅仅使用这个值来记录集合中的元素,long类型占8个字节,下边只用最低8位计算private long elements 0L;RegularEnumSet(ClassEelementType, Enum?[] universe) {super(elementType, universe);}//添加方法public boolean add(E e) {typeCheck(e);long oldElements elements;//假设原本集合为空,则elements为0(0000 0000),这是添加编号为1的枚举值,计算如下:// 先将 1 左移1位 则变成// 0000 0001 ----》 0000 0010// 然后与之前的elements做与运算// 0000 0000// 0000 0010 |//----------------// 0000 0010//这个地方设计的比较巧妙,因为long型一共占用64位,所以这里就用每一位表示当前集合中是否包含对应的枚举值//例如:0000 0010,低的第二位为1此时枚举中的第一个枚举值添加进来了//依次类推当第三位上是1时则表示第二个枚举值添加进来了//而最多只能到64位这也是为什么只有小于或等于64才创建RegularEnumSet对象elements | (1L ((Enum?)e).ordinal());return elements ! oldElements;}}//---------------umboEnumSet实现代码---------------------//class JumboEnumSetE extends EnumE extends EnumSetE {//这个集合的位向量表示。这个数组的第j个元素的第i位表示这个集合中存在宇宙[64*j i]。private long elements[];JumboEnumSet(ClassEelementType, Enum?[] universe) {super(elementType, universe);elements new long[(universe.length 63) 6];}//实现的基本思想:将是按着64位分组,当枚举值的个数大于64时,就开始分,使用枚举个数除以64看可以分几组//然后每一组再用如RegularEnumSet中添加的方法进行记录哪些元素已经添加了public boolean add(E e) {typeCheck(e);int eOrdinal e.ordinal();//判断一下要添加的枚举值应该在第几组int eWordNum eOrdinal 6;//获取到当前组的long类型的值,它是64位,按着RegularEnumSet中的add方法继续分析long oldElements elements[eWordNum];elements[eWordNum] | (1L eOrdinal);boolean result (elements[eWordNum] ! oldElements);if (result)size;return result;}}//-------------------------------创建一个EnumSet实例-------------------------// }
http://www.zqtcl.cn/news/392249/

相关文章:

  • wordpress找回管理员密码网站关键词排名优化工具
  • 望城建设局网站网站建设与维护可行性报告
  • 免费php网站模板下载手机端网站如何优化
  • 自己做的网站 打开了没有图片注册工程公司名称大全
  • 做网站的团队业绩怎么写WordPress 去掉副标题
  • 学校网页网站模板wordpress更换域名还是之前链接
  • 市面上有什么搭建网站工作室石家庄做网站和宣传的
  • 视频图站主题 wordpress快速收录提交入口
  • 外贸视频网站投资理财网站开发
  • 专业建设网站多少钱铜川网站seo
  • 海外网站seo优化wordpress的代码逻辑
  • 怎样帮别人做网站哪有网站给光头强做面
  • 聊城营销网站建设价格网站设计论文框架
  • 成都哪家网站建设做得好介绍自己的家乡遵义网站建设
  • 阳春新农村建设网站欣赏网站
  • 永久免费企业网站建设杭州个人做网站
  • 博罗中山网站建设做网站的软件 知乎
  • 广州网站开发广州亦客网络解答wordpress换空间要改
  • 丽水企业网站开发企业erp系统是什么软件
  • 好看的网站设计个人发布信息的免费平台
  • 电商网站业务流程linux上传中文wordpress
  • 广州网站定制商家外贸seo网站推广
  • 许昌大成建设集团网站wordpress自动博客插件
  • wordpress网站地图插件中国来料加工网
  • 黑龙江做网站的公司上海企业网站建设公
  • 做公众号时图片的网站安徽建设工程造价信息网站
  • 网站开发的在淘宝上是什么类目深圳做网站的大公司
  • 手机网站 html5信阳哪里做网站
  • 网站服务器多少钱一月wordpress 博客宠物
  • 怎么制作网站游戏辽宁建设工程网