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>()方法,因为在同一个类加载器下,一个类型只会被初始化一次。 ”

 

 

参考资料 / 相关推荐:

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

Java基础知识——枚举

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

【JAVA】浅谈java枚举类

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/537132.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis源码日志模块分析

看源码需要先下载源码&#xff0c;可以去Mybatis的github上的仓库进行下载&#xff0c;Mybatis 这次就先整理一下日志这一块的源码分析&#xff0c;这块相对来说比较简单而且这个模块是Mybatis的基础模块。 之前的文章有谈到过Java的日志实现&#xff0c;大家也可以参考一下&…

python手机端给电脑端发送数据_期货交易软件有哪些比较好用?分手机端和电脑端...

一、电脑端交易软件期货电脑端交易软件目前市场上用的最多的是文华财经和博易大师&#xff0c;这两个软件都是免费交易使用的。从投资者使用角度来看&#xff0c;目前电脑端文华财经的评价比博易大师高一些。当然每个投资者有自己的使用习惯&#xff0c;博易大师也有自己优点&a…

Find the Difference(leetcode389)

2019独角兽企业重金招聘Python工程师标准>>> Given two strings s and t which consist of only lowercase letters. String t is generated by random shuffling string s and then add one more letter at a random position. Find the letter that was added in …

Mybatis源码之数据源模块分析

先来看看java纯jdbc查询数据的示例&#xff1a; try {//加载对应的驱动类Class.forName("com.mysql.cj.jdbc.Driver");//创建连接Connection connection DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezoneUTC", "roo…

reactnative 获取定位_[RN] React Native 获取地理位置

import React, {Component} from react;import {StyleSheet, Text, View}from react-native;exportdefault classTestGeo extends Component {state{longitude:,//经度latitude: ,//纬度city: ,district:,street:,position:,//位置名称};componentWillMount () >{this.getPo…

第二冲刺阶段第三天

查阅资料&#xff0c;修改控件界面转载于:https://www.cnblogs.com/gyy0/p/10066452.html

Mybatis源码之缓存模块分析

缓存这个东西在很多应用中都能看到它们的身影&#xff0c;这次就讲讲在Mybatis中的缓存是怎么应用的&#xff0c;虽然说吧Mybatis中的缓存基本不怎么用&#xff0c;用的更多是第三方组件redis、MongoDB、MemCache等等。 Mybatis的缓存是基于Map实现的&#xff0c;从缓存中读写…

Mybatis源码之核心流程分析

终于谈到了Mybatis最核心的东西了&#xff0c;最核心的就是通过配置XML文件或注解中的SQL&#xff0c;直接调用接口就能执行配置好的SQL语句并封装成对应的返回类型的数据。 先看一下Mybatis使用示例&#xff1a; //创建Builder对象 SqlSessionFactoryBuilder builder new S…

mimakatz用法_两步完成利用procdump64+mimikatz获取win用户密码

使用procdump64mimikatz可实现从内存中获取明文密码工具链接&#xff1a;https://pan.baidu.com/s/1gNc9qLcNSNBohIVrAiqShw 密码&#xff1a;fc38首先得先获取到内存文件lsass.exe进程, 它用于本地安全和登陆策略,一般在进程管理器中能看到, 比如这样1.导出lsass.exeprocdump6…

ios app提交之前需要哪几个证书

1、遇到的问题 一款App在别人的机器上开发和发布&#xff0c;现在迭代更新和开发需要在一台新mac机上开发和发布。&#xff08;使用同一个开发者账号&#xff09;问题&#xff1a; 1.在新mac机器上开发并导入真机测试&#xff0c;是不是需要从别人的机器上面导处开发者证书、开…

Mybatis源码之与Spring集成包

这次讲讲Mybatis与Spring的整合&#xff0c;作为两款优秀的开源框架&#xff0c;被大众广泛使用&#xff0c;自然是需要强强联合的。 使用示例 先看一下怎么使用&#xff0c;首先需要引用这两款框架的jar包&#xff1a; <dependency>//spring-webmvc会自动去引入其他S…

hadoop主节点切换_hadoop2.0 HA的主备自动切换

在《hadoop2.0 QJM方式的HA的配置》一文中介绍了HA的配置&#xff0c;是通过手工进行主备切换的。本文在这基础上&#xff0c;继续介绍HA的主备自动切换(automatic failover)的配置。自动切换是通过配置zookeeper来实现的&#xff0c;关于zookeeper的安装和配置&#xff0c;在这…

Mybatis源码之插件模块分析

总结完这个Mybatis的整体主要功能基本上就差不多完&#xff0c;还有一些细节的部分&#xff0c;后续都会记录补充。 插件这个东西一般用的比较少&#xff0c;就算用的多的插件也算是PageHelper分页插件&#xff1b; PageHelper官网&#xff1a;https://github.com/pagehelper…

AMD推出7nm高端显卡Radeon VII,直指英伟达RTX 2080

显卡战争已经发展到了2019年&#xff0c;并且变得比任何人预想的都要激烈。 CES 2019大会上&#xff0c;AMD发布了第一款消费级的 7nm GPU&#xff0c;取名&#xff1a;Radeon VII。据了解&#xff0c;这不是 AMD 的第一颗 7nm 处理器&#xff08;早期以 AI 运算为主的 Radeon …

电子绘本pdf_【孩子必看的】20本世界著名英文绘本 | PDF电子版+MP3音频

原标题&#xff1a;【孩子必看的】20本世界著名英文绘本 | PDF电子版MP3音频2 —6岁年龄段的孩子&#xff0c;自我意识逐渐萌芽&#xff0c;已经明白书是一种“特殊”的玩具&#xff0c;不在撕书、咬书、把书搬来搬去。这个阶段他们记忆力超强&#xff0c;唐诗、三字经啥的&…

Spring集成Mybatis多数据源配置

既然在整理Mybatis那就把经常用的这个多数据源的笔记也整一下吧。 Spring集成Mybatis在之前就已经提到了。Spring集成Mybatis 集成Mybatis多数据源有两种方式&#xff1a; 1、创建多个SqlSessionFactory&#xff0c;扫描每个SqlSessionFactoryBean对应的包&#xff0c;形成了…

Spring文件上传

2019独角兽企业重金招聘Python工程师标准>>> Spring文件上传 1、所需依赖包&#xff1a;commons-fileupload-1.3.1.jar2、Maven配置文件pom.xml文件中加入依赖Jar包<dependency><groupId>commons-fileupload</groupId><artifactId>commons-…

中英离线翻译mac_Instant Translate for Mac-即时翻译Mac版下载 V1.3.0-PC6苹果网

即时翻译(Instant Translate)Mac版是一款Mac平台的翻译及辞典软件&#xff0c;Instant Translate支持90的语言互翻译&#xff0c;通过ControlS切换语言&#xff0c;并且支持发音功能&#xff0c;并且支持自动检测语言并进行翻译。软件特色Instant Translate的主要特点&#xff…

基于Zookeeper使用ZkClient实现分布式锁

有段时间没写博客了&#xff0c;在整理之前写过的一套自定义框架&#xff0c;并且整理好上传值github上了&#xff0c;也有一些新功能还在开发&#xff0c;欢迎大家使用&#xff1a;一个好用的Http接口请求工具组件 可能今天这篇文章跟之前的比有些跳跃性&#xff0c;一下子就…

算法题学到的一些小语言细节

1.要学会用i&#xff1b;可以简化很多代码&#xff1a;i&#xff1b;copyFromMe(i)&#xff1b;可以写成&#xff1a;copyFromeMe(i) 2.StringBuffer也跟列表一样有append函数&#xff1b; 3.if语句是分支不能进行循环&#xff0c;要写成while才能替代循环里面的判断 4. 这里的…