一、为什么使用枚举

什么时候应该使用枚举呢?每当需要一组固定的常量的时候,如一周的天数、一年四季等。或者是在我们编译前就知道其包含的所有值的集合。

利用 public final static 完全可以实现的功能,为什么要使用枚举?

public class Season {public static final int SPRING = 1;public static final int SUMMER = 2;public static final int AUTUMN = 3;public static final int WINTER = 4;
}

(1)安全性。这种模式不是类型安全的。比如说我们设计一个函数,要求传入春夏秋冬的某个值。但是使用int类型,我们无法保证传入的值为合法。如:传入5。

(2)可读性。我们需要方便得到枚举类型的字符串表达式。int常量打印出来,我们所见到的就是一组数字,没什么用;String常量可以打印出详细信息,但是字符串的比较操作性能较低。

二、枚举的几种使用方式

用法一:常量

public enum Color {  RED, GREEN, BLANK, YELLOW
}  

用法二: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;  }  }
}  

用法三:向枚举中添加新方法

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;  }
} 

用法四:覆盖枚举的方法

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;  }
}  

用法五:实现接口

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);  }
} 

用法六:使用接口组织枚举

public interface Food {  enum Coffee implements Food{  BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  }  enum Dessert implements Food{  FRUIT, CAKE, GELATO  }
}

三、原理(代码易懂,不做详细介绍)

enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}// 反编译之后如下:
// 反编译Day.class
final class Day extends Enum
{//编译器为我们添加的静态的values()方法public static Day[] values(){return (Day[])$VALUES.clone();}//编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法public static Day valueOf(String s){return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);}//私有构造函数private Day(String s, int i){super(s, i);}//前面定义的7种枚举实例public static final Day MONDAY;public static final Day TUESDAY;public static final Day WEDNESDAY;public static final Day THURSDAY;public static final Day FRIDAY;public static final Day SATURDAY;public static final Day SUNDAY;private static final Day $VALUES[];static {    //实例化枚举实例MONDAY = new Day("MONDAY", 0);TUESDAY = new Day("TUESDAY", 1);WEDNESDAY = new Day("WEDNESDAY", 2);THURSDAY = new Day("THURSDAY", 3);FRIDAY = new Day("FRIDAY", 4);SATURDAY = new Day("SATURDAY", 5);SUNDAY = new Day("SUNDAY", 6);$VALUES = (new Day[] {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY});}
}

四、枚举保证线程安全

由上面反编译代码可以看到,“ public static final Day MONDAY; ”,static类型的属性会在类被加载之后被初始化,当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的。所以,创建一个enum类型是线程安全的。

JVM类加载机制中:

“ 并发:

  虚拟机会保证一个类的类构造器<clinit>()在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的类构造器<clinit>(),其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。

特别需要注意的是,在这种情形下,其他线程虽然会被阻塞,但如果执行<clinit>()方法的那条线程退出后,其他线程在唤醒之后不会再次进入/执行<clinit>()方法,因为在同一个类加载器下,一个类型只会被初始化一次。 ”

参考资料 / 相关推荐:

Java 7 源码学习系列(二)——Enum

Java基础知识——枚举

深入理解Java枚举类型(enum)

【JAVA】浅谈java枚举类

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

转载于:https://www.cnblogs.com/hexinwei1/p/9606266.html

JDK源码学习笔记——Enum枚举使用及原理相关推荐

  1. JDK源码学习笔记——Integer

    一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...

  2. JDK源码学习笔记——String

    1.学习jdk源码,从以下几个方面入手: 类定义(继承,实现接口等) 全局变量 方法 内部类 2.hashCode private int hash; public int hashCode() {i ...

  3. JDK源码学习笔记——TreeMap及红黑树

    找了几个分析比较到位的,不再重复写了-- Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例 [Java集合源码剖析]TreeMap源码剖析 java源码分析之TreeMap基础篇 ...

  4. Apache log4j-1.2.17源码学习笔记

    (1)Apache log4j-1.2.17源码学习笔记 http://blog.csdn.net/zilong_zilong/article/details/78715500 (2)Apache l ...

  5. RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的?

    RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 文章目录 RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 前言 项目 ...

  6. JDK源码学习-基础

    JDK源码学习 目录 基础 1. 安装 1.1 下载JDK 1.2 配置环境变量 1.3 验证 2. 简单的程序 2.1 编写代码 2.2 编译文件 2.3 执行类 3. java基本类型 基础 1. ...

  7. Java多线程之JUC包:Semaphore源码学习笔记

    若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5625536.html Semaphore是JUC ...

  8. Vuex 4源码学习笔记 - 通过Vuex源码学习E2E测试(十一)

    在上一篇笔记中:Vuex 4源码学习笔记 - 做好changelog更新日志很重要(十) 我们学到了通过conventional-changelog来生成项目的Changelog更新日志,通过更新日志 ...

  9. Vuex 4源码学习笔记 - Vuex是怎么与Vue结合?(三)

    在上一篇笔记中:Vuex源码学习笔记 - Vuex开发运行流程(二) 我们通过运行npm run dev命令来启动webpack,来开发Vuex,并在Vuex的createStore函数中添加了第一个 ...

最新文章

  1. 交叉验证分析每一折(fold of Kfold)验证数据的评估指标并绘制综合ROC曲线
  2. torch.bmm()函数的使用
  3. SAP Hybris Enterprise Commerce的一些有用链接 - 保证持续更新
  4. 带你深入浅出的分析 HashTable 源码
  5. ASM的基础使用 Android 自动化埋点方案原理剖析
  6. Thinkphp5中session用法
  7. 【备忘】Aegisub字幕制作简易方法
  8. 如何在github上创建自己的个人网站
  9. 用笔记本创建wifi热点
  10. java调用百望税控NISEC_SKSC.dll发送xml报文
  11. 用于实时操作系统固件更新开发指南的MediaTek Linkit MT2523开发平台
  12. echarts在中国地图上绘制各省指标
  13. 二、Git本地仓库基本操作——创建Git仓库、提交更新或删除文件
  14. css3-z1,z-index
  15. 融合多策略的改进麻雀搜索算法-附代码
  16. [AHK]Bing Desktop Wallpaper Changer(必应壁纸随心换)
  17. 用计算机播放vcd教案,六年级信息技术下册 第六课制作班级VCD1教案 华中师大版...
  18. React 小记 start脚本
  19. php搭建markdown云笔记_使用 Leanote 搭建自己专属的云笔记
  20. 我是小R,昨晚我好像把B站搞崩了!

热门文章

  1. matlab实验函数编写与程序设计,matlab实验四函数编写与程序设计
  2. mysql查看服务器版本sql_云服务器Windows系统查看mysql版本
  3. java对外发布接口文档_java之接口文档规范
  4. php mysql删除失败_php mysql删除的代码哪里出错了?
  5. archives_do.php,织梦后台文章管理中增加批量添加tag标签功能
  6. oracle中存储过程和函数有什么区别,Oracle中存储过程和函数的区别
  7. python升级命令debian_debian python 2.7.11 升级
  8. oracle rman备份整库,RMAN备份恢复整个库
  9. linux内核 默认路由表,[Linux] linux路由表-Go语言中文社区
  10. mysql error log清理_手动删除mysql日志/var/log/mysql/error.log导致的mysql无法启动