java单例之enum实现方式
传统的两私有一公开(私有构造方法、私有静态实例(懒实例化/直接实例化)、公开的静态获取方法)涉及线程安全问题(即使有多重检查锁也可以通过反射破坏单例),
目前最为安全的实现单例的方法是通过内部静态enum的方法来实现,因为JVM会保证enum不能被反射并且构造器方法只执行一次。
实现方法如下:
/** * 使用枚举的单例模式 * * @author yzl * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class EnumSingleton{ private EnumSingleton(){} public static EnumSingleton getInstance(){ return Singleton.INSTANCE.getInstance(); } private static enum Singleton{ INSTANCE; private EnumSingleton singleton; //JVM会保证此方法绝对只调用一次 private Singleton(){ singleton = new EnumSingleton(); } public EnumSingleton getInstance(){ return singleton; } } }
测试方法:
public static void main(String[] args) { EnumSingleton obj1 = EnumSingleton.getInstance(); EnumSingleton obj2 = EnumSingleton.getInstance(); //输出结果:obj1==obj2?true System.out.println("obj1==obj2?" + (obj1==obj2)); }
扩展应用,观察下面的例子
public class Test{ //初始化一些东西 static{ } }
这是一个很常见的类内部的静态资源初始化的写法(其实也就是单例的另外一种表现-只执行一次),但是将代码都写在static块下会看起来很不优雅,可以利用上面的enum单例模式来进行初始化操作。
见例子:
import java.util.ArrayList; import java.util.List; /** * 初始化的优雅实现 * 可以在static处调用, * 也可以在普通方法里调用,都保证只初始化一次 * * 当然将enum块的代码直接放到StaticInitTest类的private static 方法里做也是可以的 * * @author yzl * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class StaticInitTest { private static List<Integer> dataList = null; static{ dataList = Singleton.INSTANCE.init(); } /** * * 单例模式来填充数据 * * @author yzl * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ private static enum Singleton { INSTANCE; private List<Integer> list; private Singleton(){ fillData(); } /** * * 初始化数据 * * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ private void fillData(){ list = new ArrayList<Integer>(5); for(int i =1; i<6; i++){ list.add(i); } } /** * * 初始化的入口 * * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public List<Integer> init(){ return list; } } }