《Effective Java》第3条:用私有构造器或枚举类型强化Singleton属性

       Singleton指仅仅被实例一次的类,它可以控制实例个数节省系统资源,当要求系统中类对象只允许一个实例对象,那么Singleton是一个好的选择.

      《Effective Java》提供了3种Singleton的实现方式

一:私有构造器

      公有的静态成员是个final域. 私有构造器仅被调用一次,用来实例化公有静态成员.

      由于只有私有构造器而没有其他构造器,所以保证了全局唯一性:一旦类别实例化,只会存在一个实例

      在这种情况下可以通过反射调用私有构造器,所以可以修改构造器,当创建第二个实例的时候抛出异常.

二:公有的成员是个静态工厂方法

      懒汉式与饿汉式都是通过这种方式达到单例的效果.

//饿汉式
public class Singleton{
  private Singleton(){

  }
  private static final Singleton instance = new Singleton();
  public static Singleton getInstance(){
    return instance;
  }
}

//懒汉式
public class Singleton {
    private static Singleton instance = null;
    private static Object lockObject = new Object();
    //私有构造方法
    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null){
            synchronized (lockObject){
                if (instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

三:编写一个包含单元素的枚举类型

     这种放法更加的简洁,无偿的提供序列化禁止,绝对防止多次实例化,在面对复杂的序列化或者反射攻击时依然能够达到效果.

为什么枚举可以实现单例:

  枚举来说,其实Enum就是一个普通的类,它继承自java.lang.Enum类。

public enum DataSourceEnum {
    DATASOURCE;
}  

把上面枚举编译后的字节码反编译,得到的代码如下:

public final class DataSourceEnum extends Enum<DataSourceEnum> {
      public static final DataSourceEnum DATASOURCE;
      public static DataSourceEnum[] values();
      public static DataSourceEnum valueOf(String s);
      static {};
}

由反编译后的代码可知,DATASOURCE 被声明为 static 的,可以知道虚拟机会保证一个类的<clinit>() 方法在多线程环境中被正确的加锁、同步。所以,枚举实现是在实例化时是线程安全。

接下来看看序列化问题:

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

public enum DataSourceEnum {
    DATASOURCE;
}  

由此可知,枚举天生保证序列化单例

Spring中的Singleton

Spring对bean实例的创建是采用单例注册表的方式进行实现的,而这个注册表的缓存是HashMap对象,如果配置文件中的配置信息不要求使用单例,Spring会采用新建实例的方式返回对象实例.

具体实现方法尚未深究,留待以后仔细研究.

猜你喜欢

转载自blog.csdn.net/qq_34332035/article/details/81671449
今日推荐