枚举实现单例

一.为什么使用枚举

  • 单例的枚举实现在Effective Java一书中提到。因为其功能完善,使用简介,无偿地提供了序列化机制,在面对复杂的序列化或者反射攻击时任然可以绝对防止多次实例化等优点,被作者所推崇。

二.代码体现

  • 模拟一个数据库连接类
public enum  DataSourceEnum {
    DATASOURCE;
    private DBConnection connection = null;
    private DataSourceEnum(){
        connection = new DBConnection();
    }
    public DBConnection getConnection(){
        return connection;
    }
}
public class DBConnection {
}
public class Test {
    public static void main(String[] args) {
        DBConnection conn1 = DataSourceEnum.DATASOURCE.getConnection();
        DBConnection conn2 = DataSourceEnum.DATASOURCE.getConnection();
        System.out.println(conn1 == conn2);
    }
}
  • 输出结果为true

  • 可以看一下DataSourceEnum类的反编译代码

public final class DataSourceEnum extends Enum
{
    public static DataSourceEnum[] values(){
        return (DataSourceEnum[])$VALUES.clone();
    }
	//toString的逆方法,返回指定名字,给定类的枚举常量
    public static DataSourceEnum valueOf(String name){
        return (DataSourceEnum)Enum.valueOf(creational/singleton/dbconn/DataSourceEnum, name);
    }
	//私有构造函数,参数有 此枚举常量的名称,枚举常量的序号
    private DataSourceEnum(String s, int i){
        super(s, i);
        //单例对象的属性
        connection = null;
        connection = new DBConnection();
    }

    public DBConnection getConnection(){
        return connection;
    }
	//单例对象
    public static final DataSourceEnum DATASOURCE;
    //单例对象的属性
    private DBConnection connection;
    private static final DataSourceEnum $VALUES[];
    static 
    {
    	//与饿汉式相似,类初始化时创建单例对象
        DATASOURCE = new DataSourceEnum("DATASOURCE", 0);
        $VALUES = (new DataSourceEnum[] {
            DATASOURCE
        });
    }
}

  • Java规范字规定,每个枚举类型及其定义的枚举变量在JVM中都是唯一的,因此在枚举类型的序列化和反序列化上,Java做了特殊的规定。在序列化的时候Java仅仅是将枚举对象的name属性输到结果中,反序列化的时候则是通过java.lang.EnumvalueOf()方法来根据名字查找枚举对象。也就是说,序列化的时候只将DATASOURCE这个名称输出,反序列化的时候再通过这个名称,查找对应的枚举类型,因此反序列化后的实例也会和之前被序列化的对象实例相同。

你可能感兴趣的:(设计模式)