目录
1.最重要思想
构造器私有
2.饿汉式单例
/**
* 饿汉式
* 问题:类加载时就初始化,不管你用不用,浪费内存
*/
public class HungryMan {
private HungryMan(){
}
private static HungryMan hungryMan = new HungryMan();
public static HungryMan getInstance(){
return hungryMan;
}
}
3.懒汉式单例
3.1 单线程可用
/**
* 懒汉式初始形态
* 单线程的情况下可用
*/
public class LazyMan01 {
private LazyMan01(){};
private static LazyMan01 lazyMan01;
public static LazyMan01 getInstance(){
if (lazyMan01 == null){
lazyMan01 = new LazyMan01();
}
return lazyMan01;
}
}
3.2 多线程可用
/**
* 多线程可用,但是反射可破坏
* double check 双重检查锁
*/
public class LazyMan02 {
/**
* 可以使用特殊标识符防止反射破坏单例,但仍有极端问题
private static Boolean TAG = false;
private LazyMan02(){
synchronized (LazyMan02.class){
if (TAG == false){
TAG = true;
}else {
throw new RuntimeException("不要用反射破坏单例");
}
}
};*/
private LazyMan02(){};
private volatile static LazyMan02 lazyMan02;//volatile 防止指令重排
public static LazyMan02 getInstance(){
if (lazyMan02==null){
synchronized (LazyMan02.class){
if (lazyMan02==null){
lazyMan02=new LazyMan02();
}
}
}
return lazyMan02;
}
}
3.2 静态内部类
/**
* 静态内部类的方法
* 同样反射可破坏
*/
public class Holder {
private Holder(){};
private static Holder getInstance(){
return HolderClass.Holder;
}
public static class HolderClass{
public static final Holder Holder = new Holder();
}
}
3.4 枚举
反射为什么不能破坏枚举?
Constructor<LazyMan02> declaredConstructor =
LazyMan02.class.getDeclaredConstructor(null);//获得构造器
declaredConstructor.setAccessible(true);//无视私有的构造器
LazyMan02 lazyMan021 = declaredConstructor.newInstance();
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
//当一个类是枚举的时候不能被反射破坏
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
枚举实现单例模式
package shejimoshi.danli;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 枚举可以简单使用,并且防止反射破坏
*/
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
};
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
EnumSingle instance = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
EnumSingle instance1 = declaredConstructor.newInstance();//报错
}
}
当我们使用反射破坏的时候会显示,为什么不是Cannot reflectively create enum objects
反编译我们的class文件:发现空参构造函数是存在的。那证明这个文件肯定是反编译出了问题

下载jad反编译软件,随后反编译,在对应的文件找反编译后的java文件。
反编译后的内容
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public final class EnumSingle extends Enum
{
public static EnumSingle[] values()
{
return (EnumSingle[])$VALUES.clone();
}
public static EnumSingle valueOf(String name)
{
return (EnumSingle)Enum.valueOf(shejimoshi/danli/EnumSingle, name);
}
private EnumSingle(String s, int i)//只有一个需要传入string和int的
{
super(s, i);
}
public EnumSingle getInstance()
{
return INSTANCE;
}
public static void main(String args[])
throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException
{
EnumSingle instance = INSTANCE;
Constructor declaredConstructor = shejimoshi/danli/EnumSingle.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
EnumSingle instance1 = (EnumSingle)declaredConstructor.newInstance(new Object[0]);
}
public static final EnumSingle INSTANCE;
private static final EnumSingle $VALUES[];
static
{
INSTANCE = new EnumSingle("INSTANCE", 0);
$VALUES = (new EnumSingle[] {
INSTANCE
});
}
}
将对应空参改为传入String和int
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
EnumSingle instance = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance1 = declaredConstructor.newInstance();
}
正常显示

4035

被折叠的 条评论
为什么被折叠?



