创建和销毁对象——用私有构造器或者枚举类型强化Singleton属性
参考资料:《Effective Java》、《Java核心技术 卷1》、https://www.cnblogs.com/zhaosq/p/10135362.html
基础回顾
1.什么是枚举?
有时候一个变量的取值只在一个有限的集合内,比如衣服的大小,就可以用到枚举。
//自定义枚举类型 enum Size {S,M,L,X}; //声明Size类型的变量 Size size=Size.M
枚举类型只是存储这个枚举指定的变量,如上面的size只能是S,M,L,X。
实际上,enum是与类同级的,但是又不能完全当作类。
与类的区别在于:
1.类的关键字是class,枚举是enum
2.类可以在方法内部,也就是局部内部类。但是enum不能在方法内声明,只能在类的外部或者类的内部方法的外部声明。
相同点就是enum内也可以写一些构造器、方法等
2.什么是Singleton
Singleton就是单例模式,指一个类只能有一个实例。比如我们常常使用的Windows系统,大家随变点击一个系统功能的图标,比如此电脑或者垃圾箱,不管点击多少次,永远只有那一个窗口,其实这就是单例模式的一种表现。
单例模式的实现主要通过以下两个步骤:
1.将该类的构造器私有化,这样其他类就不能通过构造器实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。
2.然后提供的这个静态方法需要进行判断,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。
代码如下:
public class EJ01_03 { //私有构造器仅被调用这一次,用来实例化静态final域INSTANCE private static final EJ01_03 INSTANCE=new EJ01_03(); //私有化构造器,这样就不能实例化这个类了 private EJ01_03(){}; //外部只能调用这个方法来获取这个类的实例,但是这个方法返回的都是同一个实例 public static EJ01_03 getInstance(){ return INSTANCE; } }
这样就只能通过如下代码获取EJ01_03类的实例化对象。所有对getInstance的调用,都会返回同一个对象引用
EJ01_03 ej3=EJ01_03.getInstance();
用枚举实现单例
在用枚举实现单例之前,需要更深入的了解一下枚举。
枚举的定义如下:
enum Size {S,M,L,X};
但是通过编译器编译过后,上面的代码被编译成一个Size类,主要内容如下:
class Size{ public static final Size S; public static final Size M; public static final Size L; public static final Size X; //实例化 static { S=new Size(); M=new Size(); L=new Size(); X=new Size(); } }
通过上面的代码可以看出,S、M、L、X其实都是静态的final域。
而实现单例模式正好需要一个静态的final域。所以用枚举实现单例代码如下:
class EnumSingleton{} enum Singleton { INSTANCE; //单例对象是EnumSingleton,所以需要声明一个EnumSinleton变量。 private EnumSingleton instance; //枚举的构造方法默认是私有的,所以不需要加private Singleton() { instance = new EnumSingleton(); } public EnumSingleton getInstance() { return instance; } }
//使用枚举类型时会调用构造函数,然后INSTANCE在下面提到了,是唯一的,INSTANCE其实就是new Singleton()。所以可以通过INSTANCE调用getInstance() EnumSingleton enumSingleton2=Singleton.INSTANCE.getInstance();
在Java中,每一个枚举变量都是唯一的。枚举单例的方法虽然与普通的方法相似,但是无偿的提供了序列化机制,绝对防止了多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。