转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10843644.html

一:枚举的用法

  1、定义和组织常量

  在JDK1.5之前,我们定义常量都是:public static fianl....。有了枚举之后,我们可以把相关的常量定义到一个枚举类里,而且枚举类也提供了比常量更多的操作方法来操纵。

  用法举例:

public enum EnumTest {
MON, TUE, WED, THU, FRI, SAT, SUN;
}

看不懂没关系,上面的枚举类定义原理在下文中再解释。

  2、用于switch

switch语句只支持常量值作为判断依据,枚举类型是个特例。

  用法举例:

//定义枚举
enum Signal {
GREEN, YELLOW, RED
} //测试
public class TrafficLight {
Signal color = Signal.RED; public void change() {
switch (color) { //使用枚举来作比较
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}

  3、向枚举中自定义属性和方法

  我们在定义枚举时,其实是在定义一个Enum类的子类,我们可以往其中添加自定义的属性和方法。

  但是要注意:我们需要在枚举类中先定义enum实例,用分号 ; 隔开。然后才是成员变量和方法的定义。如果顺序错了会导致编译错误。【实际开发时有可能反过来,先定义成员变量和方法,再添加枚举实例】

用法举例:

public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4); //定义枚举实例 // 自定义成员变量
private String name;
private int index; // 定义构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 添加方法
public static String getName(int index) {
for (Color c : Color.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
// get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}

  4、重写Enum类中的方法

  定义枚举类的过程其实是定义Enum类的子类的过程,Enum类定义了一些方法,这些方法我们可以在自己定义枚举类时重写,最常见的是:重写toString()函数,返回自定义成员变量的拼接结果。

  用法举例:

public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 自定义成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//重写父类方法
@Override
public String toString() {
return this.index+"_"+this.name;
}
}

  5、实现接口

  前面提到,用enum关键字定义枚举类时,其实是定义Enum类的子类。也就是说,我们定义的枚举类是继承自 Enum类的。

  而Java中是不支持多继承的,那如果多个枚举类型都有通用的行为时,如何进行抽象组织呢?——答案是:实现接口。

  我们可以在定义枚举类时,实现接口,重写接口中的方法来达到增加行为的目的。

  

//定义接口
public interface Behaviour {
void print();
String getInfo();
} //定义枚举类,实现接口
public enum Color implements Behaviour{
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//接口方法
@Override
public String getInfo() {
return this.name;
}
//接口方法
@Override
public void print() {
System.out.println(this.index+":"+this.name);
}
}

  6、EnumSet的使用

  java.util.EnumSet是枚举类型的集合类,可以保证集合中的枚举元素不重复。

// EnumSet的使用
EnumSet<EnumTest> weekSet = EnumSet.allOf(aEnum.class); //将枚举类.class文件作为参数。至于为何使用.class文件,在下文中揭晓

  7、EnumMap的使用

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

 // EnumMap的使用
EnumMap<自定义Enum类型, String> weekMap = new EnumMap(aEnum.class); weekMap.put(aEnum.MON, "星期一");
weekMap.put(aEnumt.TUE, "星期二");

二:枚举的实现——Enum类了解

   enum这个关键字,包含了:继承Enum类,定义当前类 的意思,所创建的类型都是 java.lang.Enum 类的子类。

  虽然都是定义类,但是enum关键字和class关键字的约束行为不同,class定义的类,通过new操作创建对象,想new几个就几个,而enum关键字定义的类,其实例对象,只能在这个enum类中定义好,它的实例是有限的,限制了某些东西的范围。

  如果我们不自定义枚举类的成员变量和构造方法,只定义枚举实例,则枚举实例内容都将以字符串的形式存在,在类加载的时候会通过 protected Enum(String name, int ordinal) 构造函数被创建为基本的Enum实例。 

  回到第一点中的第一个用法:

public enum EnumTest {
MON, TUE, WED, THU, FRI, SAT, SUN;
}

  其解释过程为:

new Enum<EnumTest>("MON",0);
new Enum<EnumTest>("TUE",1);
new Enum<EnumTest>("WED",2);
... ...

  也就是说,这段代码实际上调用了7次 Enum(String name, int ordinal)。

  枚举类经过编译器编译之后产生的是一个class文件,该class文件经过反编译可以看到实际上是生成了一个类,该类继承了java.lang.Enum<E>。

  也就是说,enum 实际上就是一个 class,只不过 java 编译器帮我们做了语法的解析和编译而已,我们的枚举值也被解释成了static final修饰的常量。

public class com.hmw.test.EnumTest extends java.lang.Enum{
  //我们可以看到:定义的时候的枚举值,被实例化了
public static final com.hmw.test.EnumTest MON;
public static final com.hmw.test.EnumTest TUE;
public static final com.hmw.test.EnumTest WED;
public static final com.hmw.test.EnumTest THU;
public static final com.hmw.test.EnumTest FRI;
public static final com.hmw.test.EnumTest SAT;
public static final com.hmw.test.EnumTest SUN;
static {};
public int getValue();
public boolean isRest();
public static com.hmw.test.EnumTest[] values();
public static com.hmw.test.EnumTest valueOf(java.lang.String);
com.hmw.test.EnumTest(java.lang.String, int, int, com.hmw.test.EnumTest);
}

  

  Enum类中封装了一些方法,最常用的是 compareTo 和 toString。

int compareTo(E o)
比较此枚举与指定对象的顺序。 Class<E> getDeclaringClass()
返回与此枚举常量的枚举类型相对应的 Class 对象。 String name()
返回此枚举常量的名称,在其枚举声明中对其进行声明。 int ordinal()
返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。 String toString() 返回枚举常量的名称,它包含在声明中。 static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
返回带指定名称的指定枚举类型的枚举常量。

三:使用枚举实现单例模式

  参考我的另一片博文;https://www.cnblogs.com/ygj0930/p/10845530.html

   

四:Java 枚举如何比较

  枚举实例可以使用 == 作比较,也可以 使用 equals() 作比较,二者结果一样,因为Enum类重写了 equals()方法,其实质还是使用 == 作比较的。

public final boolean equals(Object other) {
return this==other;
}

五:switch 对枚举的支持

来看一则 switch中用枚举作case的代码反编译结果:

 package com.example.demo; import java.io.PrintStream;
ab public class EnumTest{ public EnumTest(){}
public static transient void main(string args[])
{ab a = ab.aaa;
class _anm1 {} switch(_cls1..SwitchMap.com.example.demo.ab[a.ordinal()]) //取的是枚举的ordinal()方法的返回值
{
case 1: // '\001'system.out.println("aaa");
// fall through case 2: // '\002'system.out.println("bbb");
// fall through
default:return; } }}

  结合上文中第四点Enum类的解读,ordinal()方法返回的是枚举类中的ordinal成员变量值(一个int值),因此switch中用枚举类型作比较时实际上是用枚举值的ordinal值作比较的。

六:枚举的序列化与反序列化

  枚举类型在序列化时仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象

  同时,编译器禁止重写枚举类型的writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。

    

七:枚举的线程安全性问题——为什么说枚举类型是线程安全的

  从第二点,枚举类反编译得到的代码我们可以看到,枚举类编译出来的属性都是static类型的,而static类型的属性会在类被加载之后初始化,而Java类的加载和初始化过程都是线程安全的,所以创建一个enum类型是线程安全的。

  

Java枚举的用法和原理深入的更多相关文章

  1. 「Java基本功」一文读懂Java内部类的用法和原理

    内部类初探 一.什么是内部类? 内部类是指在一个外部类的内部再定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的.内部类可为静态,可用protected和private修饰(而外部类只能 ...

  2. 夯实Java基础系列14:深入理解Java枚举类

    目录 初探枚举类 枚举类-语法 枚举类的具体使用 使用枚举类的注意事项 枚举类的实现原理 枚举类实战 实战一无参 实战二有一参 实战三有两参 枚举类总结 枚举 API 总结 参考文章 微信公众号 Ja ...

  3. Java 枚举(enum)的学习

    Java 枚举(enum)的学习 本文转自:https://blog.csdn.net/javazejian/article/details/71333103 枚举的定义 在定义枚举类型时我们使用的关 ...

  4. 【转】Java 枚举7常见种用法

    原文网址:http://softbeta.iteye.com/blog/1185573 Java 枚举7常见种用法 博客分类: java java枚举enmu  原创地址:http://blog.li ...

  5. Java枚举类使用

    用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. p ...

  6. MariaDB/MySQL备份和恢复(三):xtrabackup用法和原理详述

    本文目录: 1.安装xtrabackup 2.备份锁 3.xtrabackup备份原理说明 3.1 备份过程(backup阶段) 3.2 准备过程(preparing阶段) 3.3 恢复过程(copy ...

  7. Java基础15:深入剖析Java枚举类

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  8. Java 枚举(enum) 详解7种常见的用法

    Java 枚举(enum) 详解7种常见的用法 来源 https://blog.csdn.net/qq_27093465/article/details/52180865 JDK1.5引入了新的类型— ...

  9. 理解Java枚举类型

    (参考资料:深入理解java enum) 1.原理:对编译后的class文件javap反编译可以看出,定义的枚举类继承自java.lang.Enum抽象类且通过public static final定 ...

随机推荐

  1. .NET三种异步模式(APM、EAP、TAP)

    APM模式: .net 1.0时期就提出的一种异步模式,并且基于IAsyncResult接口实现BeginXXX和EndXXX类似的方法. .net中有很多类实现了该模式(比如HttpWebReque ...

  2. ESP8266 LUA脚本语言开发: 准备工作-LUA开发说明

    前言 开发Lua需要使用这个软件 注:该软件需要按照JDK  即 JAVA虚拟机,如果没有安装过JDK,请先看JDK安装教程安装JDK USB线连接开发板接入电脑 选择自己的串口号 波特率115200 ...

  3. 不使用xftp上传/下载文件到linux

    yum install lrzsz    # 安装软件 window端上传到linux端: 1. window端先压缩需上传的文件 2. linux端运行命令rz 3. 在弹出的窗口选择压缩好的文件, ...

  4. Codeforces 1204D Kirk and a Binary String - 数学

    题目传送门 传送门 群除我均会猜结论/找规律,sad.... 以下内容只保证代码能过system test,证明应该都是在纯口胡 约定下文中的$LIS$表示最长不下降子序列. 定义$zero(s)$表 ...

  5. Android保存的文件显示到文件管理的最近文件和下载列表中

    发现Android开发每搞一个和系统扯上关系的功能都要磨死人,对新手真不友好.运气不好难以快速精准的找到有效的资料

  6. 第24课 std::thread线程类及传参问题

    一. std::thread类 (一)thread类摘要及分析 class thread { // class for observing and managing threads public: c ...

  7. SqlServer 通过日志恢复数据库

    前期工作 查看数据属性,确保下条件: 1.数据库属性->选项->恢复模式=完整 2.建好库以后.一个数据库完整的数据备份 3.到出事期间日志没有你间断 4.记录出事的准确时间 一.数据准备 ...

  8. iOS依赖库管理工具之CocoaPods

    CocoaPods 是开发 OS X 和 iOS 应用程序的一个第三方库的依赖管理工具.利用 CocoaPods,可以定义自己的依赖关系库 (称作 pods),并且随着时间的变化,在整个开发环境中对第 ...

  9. 【linux】lvm扩展根分区

    lvm扩展根目录 1.lvm的基本概念 physical volume (PV) 通常是一快硬盘.相当于一个物理设备,磁盘空间物理卷PV. volume group (VG) 相当于LVM的卷组,属于 ...

  10. vue样式绑定、事件监听、表单输入绑定、响应接口

    1.样式绑定 操作元素的 class 列表和内联样式是数据绑定的一个常见需求.因为它们都是属性,所以我们可以用 v-bind 处理它们:只需要通过表达式计算出字符串结果即可.不过,字符串拼接麻烦且易错 ...