JDK源码学习笔记——Enum枚举使用及原理
一、为什么使用枚举
什么时候应该使用枚举呢?每当需要一组固定的常量的时候,如一周的天数、一年四季等。或者是在我们编译前就知道其包含的所有值的集合。
利用 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>()方法,因为在同一个类加载器下,一个类型只会被初始化一次。 ”
参考资料 / 相关推荐:
JDK源码学习笔记——Enum枚举使用及原理的更多相关文章
- JDK源码学习笔记——LinkedHashMap
HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序. LinkedHashMap保证了元素迭代的顺序.该迭代顺序可以是插入顺序或者是访问顺序.通过维护一个 ...
- JDK源码学习笔记——String
1.学习jdk源码,从以下几个方面入手: 类定义(继承,实现接口等) 全局变量 方法 内部类 2.hashCode private int hash; public int hashCode() { ...
- JDK源码学习笔记——Integer
一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...
- JDK源码学习笔记——Object
一.源码解析 public class Object { /** * 一个本地方法,具体是用C(C++)在DLL中实现的,然后通过JNI调用 */ private static native void ...
- JDK源码学习笔记——HashMap
Java集合的学习先理清数据结构: 一.属性 //哈希桶,存放链表. 长度是2的N次方,或者初始化时为0. transient Node<K,V>[] table; //最大容量 2的30 ...
- JDK源码学习笔记——HashSet LinkedHashSet TreeSet
你一定听说过HashSet就是通过HashMap实现的 相信我,翻一翻HashSet的源码,秒懂!! 其实很多东西,只是没有静下心来看,只要去看,说不定一下子就明白了…… HashSet 两个属性: ...
- JDK源码学习笔记——TreeMap及红黑树
找了几个分析比较到位的,不再重复写了…… Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例 [Java集合源码剖析]TreeMap源码剖析 java源码分析之TreeMap基础篇 ...
- JDK源码学习笔记——LinkedList
一.类定义 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E& ...
- JDK源码学习笔记——ArrayList/Vector
一.类定义 public class ArrayList<E> extends AbstractList<E> implements List<E>, Random ...
随机推荐
- layui table表格字段过长,展示不完整时,鼠标放到上面展示完整信息
亲测可以直接用 1.首先每个列都有一个title,里面放入完整信息,然后写一个如下的function, function tdTitle(){ $('th').each(function(index, ...
- KL散度(Kullback–Leibler divergence)
KL散度是度量两个分布之间差异的函数.在各种变分方法中,都有它的身影. 转自:https://zhuanlan.zhihu.com/p/22464760 一维高斯分布的KL散度 多维高斯分布的KL散度 ...
- Linux机器如何在公司内网配置代理
一.通过上网认证 必须在图形界面下使用浏览器(如Firefox)完成上网认证过程. 请先确保本机已经可以正常访问公司内部网络. Firefox上配置代理: 1)打开Firefox首选项,[高级]-[网 ...
- The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context,
在iis7.0布署网站后运行的错误,大致意思是:数据保护操作是不成功的.这可能是由于没有为当前线程的用户加载用户配置文件的导致 解决办法: 先为自己的网站新建一个应用程序池,然后新建的应用程序池上右键 ...
- fsevents npm install是报错
npm install 安装插件的时候,fsevents报错,这是node 8.x版本的问题,解决办法,把node 版本切换到6.x
- web性能优化之js图片懒加载
html <div class="container"> <ul> <li> <div id="first" clas ...
- Filebeat入门
一.安装filebeat 简介 Beats 是安装在服务器上的数据中转代理. Beats 可以将数据直接传输到 Elasticsearch 或传输到 Logstash . Beats 有多种类型,可以 ...
- PHP性能调优---PHP调试工具Xdebug安装配置教程
说到PHP代码调试,对于有经验的PHPer,通过echo.print_r.var_dump函数,或PHP开发工具zend studio.editplus可解决大部分问题,但是对于PHP入门学习的童鞋来 ...
- Entity Framework Code First 在Object Join Linq查询时出现全表查询的语句。
最近一个项目,使用微软的Entity Framework的ORM框架的项目,部署到现场后,出现了系统缓慢,多个客户端的内存溢出崩溃的问题. 打开了SQL Server Profiler(SQL Ser ...
- 饼图tooltip
@{ ViewBag.Title = "pie"; } <h2>pie</h2> <div id="main" style=&qu ...