Java修炼之路——基础篇——枚举
枚举的用法
每个枚举变量其实都是枚举类的一个实例。
枚举与单例
各种模式的单例模式,包括枚举实现的单例
//懒汉模式
class SingletonA {private static SingletonA instance = new SingletonA();//保证不能通过new SingletonB的方式创建对象private SingletonA(){}public static SingletonA getInstance() {return instance;}
}//保证效率的懒加载
class SingletonB {private static SingletonB instance;private SingletonB(){}public static SingletonB getInstance() {if(instance == null) {synchronized (SingletonB.class) {if (instance == null) {instance = new SingletonB();}}}return instance;}
}//内部类懒汉模式
class SingletonC {private SingletonC(){}private static class SingletonHolder {private static final SingletonC instance = new SingletonC();}public SingletonC getInstance() {return SingletonHolder.instance;}
}//内部枚举类懒加载模式
class SingletonD {private SingletonD(){}private enum EnumSingleton {instance;//因为枚举变量是static final的,所以如果不是定义时声明,那只能在构造方法中实例化,并且有且只能实例化一次。//所以保证了resource对象的单例性。private SingletonD singletonD;private EnumSingleton() {singletonD = new SingletonD();}}public SingletonD getInstance() {return EnumSingleton.instance.singletonD;}
}
枚举如何比较
可以用equals(),也可以用==,推荐使用==
enum的equals()方法实现如下:
public final boolean equals(Object other) {return this==other;}
可以看出,也是调用的==实现的。
官方文档说明如下:
JLS 8.9 Enums 一个枚举类型除了定义的那些枚举常量外没有其他实例了。 试图明确地说明一种枚举类型是会导致编译期异常。
在枚举中final clone方法确保枚举常量从不会被克隆,而且序列化机制会确保从不会因为反序列化而创造复制的实例。
枚举类型的反射实例化也是被禁止的。
总之,以上内容确保了除了定义的枚举常量之外,没有枚举类型实例。
另外,==和equals()的不同如下:
== 不会抛出 NullPointerException
enum Color { BLACK, WHITE };Color nothing = null;
if (nothing == Color.BLACK); // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException== 在编译期检测类型兼容性
enum Color { BLACK, WHITE };
enum Chiral { LEFT, RIGHT };if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine
if (Color.BLACK == Chiral.LEFT); // DOESN'T COMPILE!!! Incompatible types!
总而言之,在枚举比较上使用 == , 因为: 1. 能正常工作 2. 更快 3. 编译期是安全的 4. 运行时也是安全的
switch 对枚举的支持
枚举 switchcase 标签必须为枚举常量的非限定名称
用法如下:
//定义枚举
public enum Color {RED,GREEN,YELLOW;
}//使用枚举
public void compare(Color color) {switch (color) {case RED:break;case YELLOW:break; default:break;}}
枚举的线程安全性问题
枚举的序列化如何实现
枚举是线程安全的,描述如下:
1:枚举的实现方式
//定义枚举
public enum t {SPRING,SUMMER,AUTUMN,WINTER;
}
//反编译枚举类
public final class T extends Enum
{private T(String s, int i){super(s, i);}public static T[] values(){T at[];int i;T at1[];System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0, i);return at1;}public static T valueOf(String s){return (T)Enum.valueOf(demo/T, s);}public static final T SPRING;public static final T SUMMER;public static final T AUTUMN;public static final T WINTER;private static final T ENUM$VALUES[];static{SPRING = new T("SPRING", 0);SUMMER = new T("SUMMER", 1);AUTUMN = new T("AUTUMN", 2);WINTER = new T("WINTER", 3);ENUM$VALUES = (new T[] {SPRING, SUMMER, AUTUMN, WINTER});}
}
通过反编译后代码我们可以看到,public final class T extends Enum,说明,该类是继承了Enum类的,同时final关键字告诉我们,这个类也是不能被继承的。
并且方法与属性都是static的,而static类型的属性会在类被加载之后被初始化。当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的。所以,创建一个enum类型是线程安全的。
2:枚举的序列化
JavaDoc中的描述:
序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,
反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。
同时,编译器是不允许任何对这种序列化机制的定制的,
因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。
我们看一下这个valueOf方法:
public static <T extends Enum<T>>T valueOf(Class<T> enumType,String name) { T result = enumType.enumConstantDirectory().get(name); if (result != null) return result; if (name == null) throw new NullPointerException("Name is null"); throw new IllegalArgumentException( "No enum const " + enumType +"." + name); }
从代码中可以看到,代码会尝试从调用enumType这个Class对象的enumConstantDirectory()方法返回的map中获取名字为name的枚举对象,如果不存在就会抛出异常。再进一步跟到enumConstantDirectory()方法,就会发现到最后会以反射的方式调用enumType这个类型的values()静态方法,也就是上面我们看到的编译器为我们创建的那个方法,然后用返回结果填充enumType这个Class对象中的enumConstantDirectory属性。
所以,JVM对序列化有保证。
此段描述来自于:http://blog.jobbole.com/94074/
Java修炼之路——基础篇——枚举相关推荐
- Java修炼之路——基础篇——数据类型
基础数据类型: 整型(byte short int long ).浮点型.布尔型.字符型boolean:只表示一位的信息,true,false.默认为false,基本上占一字节char: 16位,2字 ...
- Java修炼之路——基础篇——Java集合类详解2
Set和List区别?Set如何保证元素不重复? Set.List都实现了Collection接口,List是有序的列表,Set是无序的集合(TreeSet有序) List实现类: ArrayList ...
- Java修炼之路——基础篇——Java集合类详解1
SynchronizedList和Vector的区别 java.util.Vector java.util.Collections.$SynchronizedList Vector用同步方法,Sync ...
- Java修炼之路——基础篇——Java关键字
1:transient 当对象被序列化时,transient阻止其修饰的对象进行序列化:当反序列化时,此对象的值不会被恢复. 2:instanceof 判断引用指向的对象,是不是某个类及其子类的实例对 ...
- Java修炼之路——基础篇——String
String 1:字符串的不可变性 什么是不可变对象?不可变对象是指创建后无法变更的对象 String为什么是不可变的?String类为final,并且内部字符数组也为final.所以String对象 ...
- Java修炼之路——基础篇——值传递
什么是值传递?引用传递? 值传递:值传递是将变量的一个副本传递到方法中,方法中如何操作该副本,都不会影响原变量的值.引用传递:引用传递是将变量的地址传递到方法中,方法中操作该变量,会对其产生影响. 为 ...
- Java修炼之路——基础篇——平台无关性
Java如何实现平台无关性? 首先说无论是哪种语言,都需要经过操作系统和CPU来完成程序的运行.平台无关性指的是程序不会因为操作系统和处理器的不同而不能运行或者发生运行错误.而不同的CPU和OS组成的 ...
- JAVA学习之路--基础篇三
目录 关于Java中从键盘输入的语句 nextxxx().next().nextLine()的区别 语句 if和if else语句 Switch语句 for语句 while和do..while bre ...
- java程序试岗内容_java程序员修炼之路基础篇四:继承
上一篇文章我跟大家聊了一下"封装",今天我们聊一下同样作为java语言三大特征之一的"继承". 简单说"继承"就是从一个已知类派生出新类的过 ...
最新文章
- 第三章:创建用户界面组件--可视化组件(一)
- (volatile int)(x)与*(volatile int *)(x)
- Verdi - GUI技能操作 Before you start (未完)
- python 操作数据库的常用SQL命令
- springboot 多数据源mybatis的两种整合方法
- Android5.0新控件
- 使用Eclipse创建maven项目
- bootstrap4 后台管理模板_开源的后台管理模板
- Python进制转换(利用栈)
- Spring Cloud Hystrix 进行服务熔断设置时,报错找不到对应的服务熔断方法
- spss和python有什么不同_python与spss的不同
- KOOCAN的影视资讯——那些惊艳到你的女鬼
- JavaWeb项目--【在线音乐播放器】onlineMusicPlayer
- c语言数字转化为英文版,(C语言编写的英语数字转化代码数字转化为用英语表达的数字.doc...
- vue加载m3u8视频格式
- C++语言风格流变史
- SQL Server安装中错误该性能计数器注册表配置单元已损坏。若要继续,必须修复该性能计数器注册表配置单元的解决
- iO逆向 触动精灵网络请求
- 求最大公约数c语言实验心得,C语言编程实训报告(合集)
- 虚拟机开启系统蓝屏报错:“终止代码:SYSTEM_SERVICE_ECXEPTION“
热门文章
- 《零基础看得懂的C语言入门教程 》——(十三)socket服务端编写
- linux下覆盖文件命令,在Linux中使用命令行进行文件覆盖的操作
- 晋中学院计算机考研,晋中学院有多少人死在考研路上
- python多线程读取数据库数据_Python基于多线程操作数据库相关知识点详解
- 中国代工厂的困惑:把大牌t恤卖到99块3件,还会有人买吗?
- 听说你趁我不在家,欺负我老婆?
- 不得了,日本出版社竟是这样吸引死宅学编程的
- js获取int类型长度_js代码比较大小前需要把string转换int
- java语言程序设计一_java语言程序设计(一)-1
- 纳尼???我JVM优化过头了,直接把异常信息优化没了?怎么办