Java enum(枚举)浅析

(一)单例模式枚举引来的思考       

     博主在之前一篇博文中引用  单例模式的7种实现的通过枚举方式实现,简单提到通过枚举类,简洁实现线程安全的单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,代码如下所示:

1 public enum SingletonEnum {
2     INSTANCE;
3     public void whateverMethod(){}
4 }

      在单例模式中,如开头简短代码使用SingletonEnum.INSTANCE进行访问,这样也就避免调用getInstance方法,更重要的是使用枚举单例的写法,我们完全不用考虑序列化和反射的问题。枚举序列化是由jvm保证的,每一个枚举类型和定义的枚举变量在JVM中都是唯一的,在枚举类型的序列化和反序列化上,Java做了特殊的规定:在序列化时Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的并禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法,从而保证了枚举实例的唯一性。

(二)枚举带来的便利 view plain

JDK1.5引入了新的类型——枚举。在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便。在枚举出现之前,如果想要表示一组特定的离散值,往往使用一些常量。例如:

[java]  view plain  copy
  1. package com.fhp.enumexample;  
  2.   
  3. public class Entity {  
  4.       
  5.     public static final int VIDEO = 1;//视频  
  6.     public static final int AUDIO = 2;//音频  
  7.     public static final int TEXT = 3;//文字  
  8.     public static final int IMAGE = 4;//图片  
  9.       
  10.     private int id;  
  11.     private int type;  
  12.       
  13.     public int getId() {  
  14.         return id;  
  15.     }  
  16.     public void setId(int id) {  
  17.         this.id = id;  
  18.     }  
  19.     public int getType() {  
  20.         return type;  
  21.     }  
  22.     public void setType(int type) {  
  23.         this.type = type;  
  24.     }  
  25.       
  26.       
  27. }  

当然,常量也不仅仅局限于int型,诸如char和String等也是不在少数。然而,无论使用什么样的类型,这样做都有很多的坏处。这些常量通常都是连续、有无穷多个值的量,而类似这种表示类别的量则是离散的,并且通常情况下只有有限个值。用连续的量去表示离散量,会产生很多问题。例如,针对上述的Entity类,如果要对Entity对象的type属性进行赋值,一般会采用如下方法:

[java]  view plain  copy
  1. Entity e = new Entity();  
  2. e.setId(10);  
  3. e.setType(2);  
这样做的缺点有:(1)代码可读性差、易用性低。由于setType()方法的参数是int型的,在阅读代码的时候往往会让读者感到一头雾水,根本不明白这个2到底是什么意思,代表的是什么类型。当然,要保证可读性,还有这样一个办法:
[java]  view plain  copy
  1. e.setType(Entity.AUDIO);  
而这样的话,问题又来了。这样做,客户端必须对这些常量去建立理解,才能了解如何去使用这个东西。说白了,在调用的时候,如果用户不到Entity类中去看看,还真不知道这个参数应该怎么传、怎么调。像是setType(2)这种用法也是在所难免,因为它完全合法,不是每个人都能够建立起用常量名代替数值,从而增加程序可读性、降低耦合性的意识。

(2)类型不安全。在用户去调用的时候,必须保证类型完全一致,同时取值范围也要正确。像是setType(-1)这样的调用是合法的,但它并不合理,今后会为程序带来种种问题。也许你会说,加一个有效性验证嘛,但是,这样做的话,又会引出下面的第(3)个问题。

(3)耦合性高,扩展性差。假如,因为某些原因,需要修改Entity类中常量的值,那么,所有用到这些常量的代码也就都需要修改——当然,要仔细地修改,万一漏了一个,那可不是开玩笑的。同时,这样做也不利于扩展。例如,假如针对类别做了一个有效性验证,如果类别增加了或者有所变动,则有效性验证也需要做对应的修改,不利于后期维护。


枚举就是为了这样的问题而诞生的。它们给出了将一个任意项同另一个项相比较的能力,并且可以在一个已定义项列表中进行迭代。枚举(在Jave中简称为enum)是一个特定类型的类。所有枚举都是Java中的新类java.lang.Enum的隐式子类。此类不能手工进行子类定义。一个简单的枚举可以是这样:

[java]  view plain  copy
  1. package com.fhp.enumexample;  
  2.   
  3. public enum TypeEnum {  
  4.     VIDEO, AUDIO, TEXT, IMAGE  
  5. }  

上面的Entity类就可以改成这样:

[java]  view plain  copy
  1. package com.fhp.enumexample;  
  2.   
  3. public class Entity {  
  4.       
  5.     private int id;  
  6.     private TypeEnum type;  
  7.       
  8.     public int getId() {  
  9.         return id;  
  10.     }  
  11.     public void setId(int id) {  
  12.         this.id = id;  
  13.     }  
  14.           
  15.     public TypeEnum getType() {  
  16.         return type;  
  17.     }  
  18.     public void setType(TypeEnum type) {  
  19.         this.type = type;  
  20.     }  
  21. }  
在为Entity对象赋值的时候,就可以这样:
[java]  view plain  copy
  1. Entity e = new Entity();  
  2. e.setId(10);  
  3. e.setType(TypeEnum.AUDIO);  

怎么看都是好了很多。在调用setType()时,可选值只有四个,否则会出现编译错误,因此可以看出,枚举是类型安全的,不会出现取值范围错误的问题。同时,客户端不需要建立对枚举中常量值的了解,使用起来很方便,并且可以容易地对枚举进行修改,而无需修改客户端。如果常量从枚举中被删除了,那么客户端将会失败并且将会收到一个错误消息。枚举中的常量名称可以被打印,因此除了仅仅得到列表中项的序号外还可以获取更多信息。这也意味着常量可用作集合的名称,例如HashMap。

        

(三)枚举的特点

1、只能有private的构造函数,无法从外部创建实例
2、枚举常量都是 public static final类型的,虽然声明中没有说明
3、enum类的values()和valueOf(String arg0)方法是编译时编译器添加的,在enum的父类Enum中没有实现
4、使用构造函数时,枚举常量的声明必须在任何声明之前,且最后需要加分号
5、查看编译后的class文件,可以看到enum类继承了java.lang.Enum类。由于enum继承了java.lang.Enum类,而Java不支持多重继承,所以enum无法再继承其他类。但是enum可以实现接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值