枚举类型(Enumerated Type)

什么是枚举?

枚举是一个被命名的整型常数的集合。在多种编程语言中都有使用(C/C++/c#/java等

示例

public enum Size {
S, M, L
};

为什么使用枚举?

在JDK1.5 之前,定义常量都是: public static fianl …… 。

类常量

public class Size {
public static final int S = 1;
public static final int M = 2;
public static final int L = 3;
}

接口常量

public interface Size {
public static final int S = 1;
public static final int M = 2;
public static final int L = 3;
}

使用

System.out.println(Size.L);//

但是这种方式存在一些缺陷,详见下面使用枚举与直接定义常量的比较。

所以在5.0 版本 SDK中,在语言层面上增加了枚举类型。

创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类(java.lang.Enum 是一个抽象类)。

枚举可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法(如添加字段,方法,遍历访问)。

枚举可以用在变量的类型匹配的检测中,可以提前发现编程错误。

枚举定义了一个变量的可使用范围。能够使程序可读性提高。

在编译期间限定类型,不允许发生越界的情况。

和一般的类中使用接口一样,enum枚举中同样可以实现接口,并实现接口中的所有方法,这样做的好处在于可以更方便地对枚举中的值进行排序、比较等操作,封装性更好。


使用枚举与直接定义常量的比较

1、两种引用方式相同,都是类名.属性”。

2、常量是直接编译在代码中的,而枚举则是一种类,你可以通过反射根据值反查出它的枚举形式是什么。

3、枚举可只定义枚举项而不定义枚举值,而类常量(或接口常量)则必须定义值,否则编译失败;

4、常量不是数据类型,只是说明被定义数据是不可变的常量;枚举是一种数据类型。

5、枚举定义了一组类型相同的成员且成员的语义清晰;常量也可以是一个数组(比如int[]),虽然其中元素类型相同,但是没法清晰指出其中元素的意义。

6、类常量可以被继承,枚举类型是不能有继承的,也就是说一个枚举常量定义完毕后,除非修改重构,否则无法做扩展。


注意:

enum 类型不支持 public 和 protected 修饰符的构造方法,因此构造函数一定要是 private 或 默认的。所以枚举对象是无法在程序中通过直接调用其构造方法来初始化的。

所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。enum枚举类型是一个不可以被继承的final类。

定义 enum 类型时候,如果是简单类型,那么最后一个枚举值后不用跟任何一个符号;但如果有定制方法,那么最后一个枚举值与后面代码要用分号';'隔开,不能用逗号或空格。

由于 enum 类型的值实际上是通过运行期构造出对象来表示的,所以在 cluster(集群) 环境下,每个虚拟机都会构造出一个同义的枚举对象。因而在做比较操作时候就需要注意,如果直接通过使用等号 ( ‘ == ’ ) 操作符,这些看似一样的枚举值一定不相等,因为这不是同一个对象实例。


方法

1、toString

返回枚举常量名。

System.out.println(Size.L.toString());//L

2、valueOf(Class, String)

Size s = (Size) Enum.valueOf(Size.class, "L");
System.out.println(s.toString());// L

3、values()

返回一个包含全部枚举值的数组。

Size[] arr = Size.values();
for (Size s : arr) {
System.out.println(s);//依次输出S、M、L
}

4、ordinal()

返回枚举常量的位置,位置从0开始计数。

System.out.println(Size.M.ordinal());//

枚举集合(EnumSet)

JDK5.0 中也增加了两个工具类 EnumSet 和 EnumMap,都放在 java.util 包中。

EnumSet 是一个针对枚举类型的高性能的 Set 接口实现。EnumSet 中装入的所有枚举对象都必须是同一种类型。

EnumSet保证集合中的元素不重复;

枚举 set 在内部表示为位向量。此表示形式非常紧凑且高效。此类的空间和时间性能应该很好,足以用作传统上基于 int 的“位标志”的替换形式,具有高品质、类型安全的优势。

如果其参数也是一个枚举 set,则批量操作(如 containsAllretainAll)也应运行得非常快。

EnumSet 支持在枚举类型的所有值的某个范围中进行迭代。

EnumMap中的 key是enum类型,而value则可以是任意类型。

注意

像大多数 collection 实现一样,EnumSet 是不同步的。

如果多个线程同时访问一个枚举 set,并且至少有一个线程修改该 set,则此枚举 set 在外部应该是同步的。这通常是通过对自然封装该枚举 set 的对象执行同步操作来完成的。

如果不存在这样的对象,则应该使用 Collections.synchronizedSet(java.util.Set) 方法来“包装”该 set。最好在创建时完成这一操作,以防止意外的非同步访问。

 Set<MyEnum> s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));

方法

1、range(E from, E to)

创建一个最初包含由两个指定端点所定义范围内的所有元素的枚举 set。

for (Size s : EnumSet.range(Size.M, Size.L)) {
System.out.println(s);// 依次打印M、L
}

2、有多个of方法用于创建一个最初包含指定元素的枚举 set。


枚举集合(EnumMap)

EnumMap 是一个高性能的 Map 接口实现。

EnumMap中的 key是enum类型,而value则可以是任意类型。

枚举映射在内部表示为数组。此表示形式非常紧凑且高效。

EnumMap 将丰富的和安全的 Map 接口与数组快速访问结合到一起,如果你希望要将一个枚举类型映射到一个值,你应该使用 EnumMap。

枚举映射根据其键的自然顺序 来维护(该顺序是声明枚举常量的顺序)。

注意

像大多数 collection 一样,EnumMap不同步的。

如果多个线程同时访问一个枚举映射,并且至少有一个线程修改该映射,则此枚举映射在外部应该是同步的。这一般通过对自然封装该枚举映射的某个对象进行同步来完成。

如果不存在这样的对象,则应该使用 Collections.synchronizedMap(java.util.Map<k, v="">) 方法来“包装”该枚举。最好在创建时完成这一操作,以防止意外的非同步访问。

     Map<EnumKey, V> m
= Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));

应用

switch (Size.M) {
case S:
System.out.println("小");
break;
case M:
System.out.println("中 ");
break;
default:
System.out.println("无");
}

自定义

public enum Size {
// Java要求必须先定义 enum 实例。必须在enum实例序列的最后添加一个分号。
S(1, "small", "小"), M(2, "middle", "中"), L(3, "large", "大");
// 定义私有变量
private int code;
private String en;
private String cn; // 构造函数,只能为私有或默认
private Size(int code, String en, String cn) {
this.code = code;
this.en = en;
this.cn = cn;
} // 覆盖toString方法
public String toString() {
return this.name() + "(编号:" + this.code + ",英文:" + this.en + ",中文:"
+ this.cn + ")";
} public int getCode() {
return code;
} public void setCode(int code) {
this.code = code;
} public String getEn() {
return en;
} public void setEn(String en) {
this.en = en;
} public String getCn() {
return cn;
} public void setCn(String cn) {
this.cn = cn;
}
}

调用

Size[] arr = Size.values();
for (Size s : arr) {
System.out.println(s);
}

打印

S(编号:1,英文:small,中文:小)
M(编号:2,英文:middle,中文:中)
L(编号:3,英文:large,中文:大)

enum与class的关系?

代码:

public enum Size {
S, M, L
};

反编译:

反编译后可以发现:

1、生成了一个Size类,该类继承了java.lang.Enum。

2、Size类被final修饰,可知枚举不能被继承。

3、属性是public static final,可知枚举项是常量,在定义枚举项时尽量用大写。

可以把枚举看成是一个不能被继承的类。

Enum 类型的更多相关文章

  1. set和enum类型的用法和区别

    mysql中的set和enum类型的用法和区别 mysql中的enum和set其实都是string类型的而且只能在指定的集合里取值, 不同的是set可以取多个值,enum只能取一个值.   1 2 3 ...

  2. MYSQL中 ENUM 类型

    MYSQL中 ENUM 类型的详细解释 ENUM类型 ENUM 是一个字符串对象,其值通常选自一个允许值列表中,该列表在表创建时的列规格说明中被明确地列举. 在下列某些情况下,值也可以是空串(&quo ...

  3. C#中enum类型

    最近碰到了枚举类型,就顺便整理下. 枚举的基类Enum,可以是除 Char 外的任何整型.不做显示声明的话,默认是整形(Int32). 声明一个Enum类型: /// <summary> ...

  4. C#遍历enum类型

    对于enum类型: 使用foreach遍历enum类型的元素并填充combox foreach ( HatchStyle hs1 in Enum.GetValues(typeof(HatchStyle ...

  5. Java中Enum类型的序列化(转)

    在Java中,对Enum类型的序列化与其他对象类型的序列化有所不同,今天就来看看到底有什么不同.下面先来看下在Java中,我们定义的Enum在被编译之后是长成什么样子的. Java代码: Java代码 ...

  6. Java 语言中 Enum 类型的使用介绍

    Enum 类型的介绍 枚举类型(Enumerated Type) 很早就出现在编程语言中,它被用来将一组类似的值包含到一种类型当中.而这种枚举类型的名称则会被定义成独一无二的类型描述符,在这一点上和常 ...

  7. java中enum类型的使用

    java 枚举类型enum 的使用 最近跟同事讨论问题的时候,突然同事提到我们为什么java 中定义的常量值不采用enmu 枚举类型,而采用public final static 类型来定义呢?以前我 ...

  8. enum类型的本质(转)

    原地址:http://www.cppblog.com/chemz/archive/2007/06/05/25578.html 至从C语言开始enum类型就被作为用户自定义分类有限集合常量的方法被引入到 ...

  9. C#基础知识回顾--C#遍历enum类型、获取enum项个数

    C#遍历enum类型 对于enum类型: 使用foreach遍历enum类型的元素并填充combox foreach ( HatchStyle hs1 in Enum.GetValues(typeof ...

  10. C#中对于Enum类型的遍历

    假设有enum类型定义为MyEnumType 则可以这样遍历:  //遍历 枚举类型中的所有成员 foreach (MyEnumType type in Enum.GetValues(typeof(M ...

随机推荐

  1. Linux下的静态库与动态库的生成与调用

    静态库与动态库 静态函数库 这类库的名字一般是libxxx.a,xxx为库的名字.利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行 ...

  2. Python 【收发邮件】

    发邮件 smtplib模块主要负责发送邮件 email模块主要负责构造邮件.这两个都是Python内置模块 smtplib.SMTP.方法 #按住Ctrl键并点击SMTP ,会看到对SMTP的解释(v ...

  3. Java坑人面试题之自动装箱和拆箱后的引用数据类型和基本数据类型的计算

    在Java1.5以后的版本中,引用类型Integer和基本数据类型int之间是可以通过自动装箱和拆箱进行计算的 例如: Integer in = 1; //it means  Integer in = ...

  4. MarkDown 语法大全查询

    目录 1. 斜体和粗体 2. 分级标题 3. 超链接 3.1. 行内式 3.2. 参考式 3.3. 自动链接 4. 锚点 5. 列表 5.1. 无序列表 5.2. 有序列表 5.3. 定义型列表 5. ...

  5. numix Docky

    今天我们介绍这款主题适用于 Docky 启动器的 numix 主题,关于 Docky 大家已经应该很熟悉了,一款类似 Mac 底部软件停放的快捷启动码头.如图: 这款主题是 Docky 的主题,如果你 ...

  6. vue 2.0 + 如何实现加入购物车,小球飞入的动画

    github源码地址:https://github.com/13476075014/node-vue/tree/master/mynodeproject/13.sell/sell 在移动端经常会有加入 ...

  7. JavaScript流程图(精简版)

    网址:https://www.processon.com/view/link/5db4f595e4b0c5553741c271 如果链接失效,请及时反馈(在评论区评论),博主会及时更新

  8. sql查询并把数据更新到另一个表中

    update OpenBills set peopleCount=(select rtNumber from Rooms where obId='ZD201005223') where obId='Z ...

  9. leetcode-21.合并有序链表 · List

    题面 合并两个排序链表. 算法 创建结果链表头*res,*p指向头,当两个链表节点都不为空时,比较节点值,值小的挂在p后面,二者(p和小者)顺次后移.知道某条链表空,跳出while循环.接着,直接将不 ...

  10. EF方式增、删、改、查(基本使用)

    右击项目——添加——新建项——数据(C#)——选择ADO.NET实体数据模型——点击添加——然后根据实体数据模型向导来一步步的做. 用到的表 using System; using System.Da ...