单例模式实现有很多种方式,常说的有比较节约内存的懒汉模式,实现比较简单的恶汉模式。
单例模式目的是整个内存这个class只能有一个对象即可,但是这传统的模式并不意味这是安全的。
传统单例模式:
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public void leaveTheBuilding() {
System.out.println("Whoa baby, I'm outta here!");
}
// This code would normally appear outside the class!
public static void main(String[] args) {
Elvis elvis = Elvis.INSTANCE;
elvis.leaveTheBuilding();
}
}
或者
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public static Elvis getInstance() {
return INSTANCE;
}
public void leaveTheBuilding() {
System.out.println("Whoa baby, I'm outta here!");
}
// This code would normally appear outside the class!
public static void main(String[] args) {
Elvis elvis = Elvis.getInstance();
elvis.leaveTheBuilding();
}
}
攻击单例模式
用第一个实现方式来看看怎么攻击单例模式:
public class Test {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Elvis elvis = Elvis.INSTANCE;
Elvis elvis2 = null;
System.out.println(elvis);
Constructor<Elvis> constructor = Elvis.class.getDeclaredConstructor();
constructor.setAccessible(true);
elvis2 = constructor.newInstance();
System.out.println(elvis2);
}
}
最终输出的结果如下:
在内存中存在两个Elvis创建的对象。攻击成功:通过反射攻击。
单例模式防御
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
if (INSTANCE != null) {
throw new RuntimeException("Elvis object has been exist!");
}
}
public void leaveTheBuilding() {
System.out.println("Whoa baby, I'm outta here!");
}
// This code would normally appear outside the class!
public static void main(String[] args) {
Elvis elvis = Elvis.INSTANCE;
elvis.leaveTheBuilding();
}
}
最终运行结果如下:
在平时的使用中可以使用枚举实现单例。
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() {
System.out.println("Whoa baby, I'm outta here!");
}
// This code would normally appear outside the class!
public static void main(String[] args) {
Elvis elvis = Elvis.INSTANCE;
elvis.leaveTheBuilding();
}
}