枚举类
为什么会有枚举类?
假如说程序中有一些颜色的状态,或者说消息的类型等,在JDK1.5之前,只能用常量来进行表示
public class TestEnum {
public static final int RED = 1;
public static final int BLACK = 2;
public static final int GREEN = 3;
public static void main(String[] args) {
int num = 1;
System.out.println(RED == num);
}
}
//true
num不是一个颜色,就与实际不太相符合,于是JDK1.5中引入了枚举类型
enum EnumColor {
RED, BLACK, GREEN;
public static void main(String[] args) {
EnumColor color = EnumColor.BLACK;
switch (color) {
case RED:
System.out.println("红色");
break;
case BLACK:
System.out.println("黑色");
break;
case GREEN:
System.out.println("绿色");
break;
}
}
}
//黑色
枚举类的使用
- 类的对象只有有限个,确定的(星期,性别,季节…)
- 当需要定义一组常量
- 使用enum定义的枚举类默认继承了java.lang. Enum类,因此不能再继承其他类
- 枚举类的构造器只能使用private权限修饰符
- 枚举类的所有实例必须在枚举类中显式列出(,分隔结尾)。列出的实例
系统会自动添加public static final修饰必须在枚举类的第一行声明枚举类对象 - 枚举不能再类外直接实例化,也不能被继承
如果枚举有参数可以添加对应的构造函数,但要注意:枚举的构造函数默认是私有的。所以不能被继承
枚举就是定义了一些状态或者常见集合,一般不需要单独实例化,用的时候到枚举类中找合适的即可
枚举的构造函数不能使用public和protected修饰。
枚举类的常用方法
方法名称 | 描述 |
---|---|
values() | 以数组形式返回枚举类型的所有成员 |
ordinal() | 获取枚举成员的索引位置 |
valueOf() | 将普通字符串转换为枚举实例 |
compareTo() | 比较两个枚举成员在定义时的顺序 |
enum EnumColor {
RED, BLACK, GREEN;
public static void main(String[] args) {
// 以数组的方式返回所有的枚举成员
EnumColor[] colors = EnumColor.values();
// 打印每个枚举成员的索引
for(int i = 0; i < colors.length; ++i){
System.out.println(colors[i] + ":" + colors[i].ordinal());
}
// 将字符串GREEN转化为枚举类型
EnumColor color1 = EnumColor.valueOf("GREEN");
System.out.println(color1);
// 在进行转换时,如果有对应的枚举类型则转换,否则抛出IllegalArgumentException
// EnumColor color2 = EnumColor.valueOf("YELLOW");//定义的枚举类没有YELLOW
// System.out.println(color2);
EnumColor color2 = EnumColor.valueOf("BLACK");//定义的枚举类没有YELLOW
System.out.println(color2);
System.out.println("-------------------------------------");
System.out.println("枚举实例的比较");
// 注意此处的比较是使用枚举成员的索引来比较了
EnumColor black = EnumColor.BLACK;
EnumColor red = EnumColor.RED;
System.out.println(black.compareTo(red));
System.out.println(BLACK.compareTo(RED));
System.out.println(RED.compareTo(BLACK));
}
//结果:
RED:0
BLACK:1
GREEN:2
GREEN
BLACK
-------------------------------------
枚举实例的比较
1
1
-1
枚举的构造
上述枚举类型有一个不太友好的地方是,枚举中只有枚举常量,拿到一个枚举常量后还是不知道其是什么颜色的,因此可以给枚举增加构造函数。
enum EnumColor {
RED("红色", 1), BLACK("黑色", 2), GREEN("绿色", 3);
private String color;
private int key;
// 注意:枚举的构造函数默认是私有的,此处不能增加非private的访问权限进行限制
/*public*/EnumColor(String color, int key){
this.color = color;
this.key = key;
}
public static EnumColor getEnum(String str){
for (EnumColor color : EnumColor.values()){
if(color.color.equals(str))
return color;
}
return null;
}
public static void main(String[] args) {
System.out.println(EnumColor.getEnum("红色"));
}
}
枚举类型能被反射吗?
不能不能不能!
通过看反射的源码,可以看出反射在通过newInstance创建对象时,会检查该类是否ENUM修饰,如果是则抛出异常,反射失败。
为什么枚举实现单例模式是安全的?
enum Singleton5 {//枚举类的单例模式
INSTANCE;
public Singleton5 getInstance(){
return INSTANCE;
}
}
1、 私有化构造器并不保险,通过反射机制调用私有构造器。而枚举类不能被反射,所以可以防止反射攻击
//模拟反射攻击
class Singleton {//双重校验锁,性能佳线程安全
private static Singleton4 instance=null;
private Singleton4() {}
public static Singleton4 getInstance() {
if(instance==null) {
synchronized (Singleton4.class) {
if (instance==null) {
//new对象分为三个操作
//分配内存
//调用构造方法初始化
//赋值
instance=new Singleton4();
}
}
}
return instance;
}
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Singleton s=Singleton.getInstance();
Singleton sUsual=Singleton.getInstance();
Constructor<Singleton> constructor=Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton sReflection=constructor.newInstance();
System.out.println(s+"\n"+sUsual+"\n"+sReflection);
System.out.println("正常情况下,实例化两个实例是否相同:"+(s==sUsual));
System.out.println("通过反射攻击单例模式情况下,实例化两个实例是否相同:"+(s==sReflection));
}
//com.lxp.pattern.singleton.Singleton@1540e19d
//com.lxp.pattern.singleton.Singleton@1540e19d
//.lxp.pattern.singleton.Singleton@677327b6
//正常情况下,实例化两个实例是否相同:true
//通过反射攻击单例模式情况下,实例化两个实例是否相同:false
2.避免序列化问题(任何一个readObject方法,不管是显式的还是默认的,它都会返回一个新建的实例,这个新建的实例不同于该类初始化时创建的实例)
枚举类的优缺点
1、优点
枚举常量更简单安全 。
枚举具有内置方法 ,代码更优雅
2. 缺点
扫描二维码关注公众号,回复:
11311982 查看本文章
不可继承,无法扩展