1. 饿汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Hungry {
private byte[] data1 = new byte[1024*1024]; private byte[] data2 = new byte[1024*1024]; private byte[] data3 = new byte[1024*1024]; private byte[] data4 = new byte[1024*1024];
private Hungry(){
}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance(){ return HUNGRY; }
}
|
2. DCL 懒汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class LazyMan { private LazyMan(){ }
private volatile static LazyMan lazyMan;
public static LazyMan getInstance(){ if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); }
} } return lazyMan; }
|
下面使用反射破坏DCL懒汉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| public class LazyMan {
private static boolean qinjiang = false;
private LazyMan(){ synchronized (LazyMan.class){ if (qinjiang == false){ qinjiang = true; }else { throw new RuntimeException("不要试图使用反射破坏异常"); } } }
private volatile static LazyMan lazyMan;
public static LazyMan getInstance(){ if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); }
} } return lazyMan; }
public static void main(String[] args) throws Exception {
Field qinjiang = LazyMan.class.getDeclaredField("qinjiang"); qinjiang.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null); declaredConstructor.setAccessible(true); LazyMan instance = declaredConstructor.newInstance();
qinjiang.set(instance,false);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance); System.out.println(instance2); }
}
|
3.其他
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Holder { private Holder(){ }
public static Holder getInstace(){ return InnerClass.HOLDER; }
public static class InnerClass{ private static final Holder HOLDER = new Holder(); }
}
|
单例不安全,可以用反射破坏!!
枚举也就一种单例,但枚举不能用反射破坏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){ return INSTANCE; }
}
class Test{
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { EnumSingle instance1 = EnumSingle.INSTANCE; Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(); declaredConstructor.setAccessible(true); EnumSingle instance2 = declaredConstructor.newInstance();
System.out.println(instance1); System.out.println(instance2);
}
}
|
如下,使用idea和javap等工具都获取到的是枚举中用的是空参构造器,事实却并非如此,使用更专业的jad反编译可得到正确的带两个参数(String,int) 的构造器。
枚举类型的最终反编译源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public final class EnumSingle extends Enum {
public static EnumSingle[] values() { return (EnumSingle[])$VALUES.clone(); }
public static EnumSingle valueOf(String name) { return (EnumSingle)Enum.valueOf(com/kuang/single/EnumSingle, name); }
private EnumSingle(String s, int i) { super(s, i); }
public EnumSingle getInstance() { return INSTANCE; }
public static final EnumSingle INSTANCE; private static final EnumSingle $VALUES[];
static { INSTANCE = new EnumSingle("INSTANCE", 0); $VALUES = (new EnumSingle[] { INSTANCE }); } }
|