饿汉式单例
多线程安全,调用时对象已经创建所以快
缺点:资源效率不高
/**
* 饿汉式单例
*/
public class Hungry {
private Hungry(){
}
private static final Hungry hungry = new Hungry();
public static Hungry getInstance(){
return hungry;
}
}
懒汉式单例改良
资源利用率高
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
public class LazyMan implements Serializable{
// 防止反序列化获取多个对象的漏洞。
// 无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。
// 实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。
private Object readResolve() throws ObjectStreamException {
return lazyMan;
}
//private static boolean flag = false;
private LazyMan(){
synchronized (LazyMan.class){
if(lazyMan !=null){
throw new RuntimeException("不要试图用反射破坏单例");
}
}
}
private volatile static LazyMan lazyMan;
//双检锁处理多线程不安全问题 双检锁的懒汉式单例 也叫DCL懒汉式
public static LazyMan getInsance(){
if(lazyMan ==null){
synchronized (LazyMan.class){
if(lazyMan ==null){
//1 分配内存
// 2执行构造方法,构建对象
//3对象赋值
//多线程情况下 123步骤可能会出现不按顺序执行,故懒汉单例模式在多线程不安全
lazyMan = new LazyMan();
}
}
}
return lazyMan;
}
private static LazyMan getSerializedSingleton(LazyMan singleton){
File file = new File("singleton");
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
LazyMan newSingleton = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(singleton);
oos.flush();
ois = new ObjectInputStream(new FileInputStream(file));
newSingleton = (LazyMan) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}finally {
if (ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(file.exists()){
file.delete();
}
}
return newSingleton;
}
public static void main(String[] args) throws Exception {
/* LazyMan insance1 = LazyMan.getInsance();
LazyMan insance2 = LazyMan.getInsance();
System.out.println(insance1.hashCode());
System.out.println(insance2.hashCode());
//利用反射破解
Constructor<? extends LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan insance3 = declaredConstructor.newInstance();
System.out.println(insance3.hashCode());*/
//双newInstance还是可以破坏
Constructor<? extends LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan insance5 = declaredConstructor.newInstance();
LazyMan insance6 = declaredConstructor.newInstance();
System.out.println(insance5.hashCode());
System.out.println(insance6.hashCode());
Field[] declaredFields = LazyMan.class.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.toString());
}
//利用序列化破坏单例
//Write Obj to file
//通过单例模式获取对象
LazyMan insance = LazyMan.getInsance();
//通过反序列化获取对象
LazyMan deserializedSingleton = LazyMan.getSerializedSingleton(insance);
System.out.println("hashCode of singleton:"+insance);
System.out.println("hashCode of deserializedSingleton:"+deserializedSingleton);
System.out.println(insance == deserializedSingleton);
}
}
枚举类
防止反射,序列化影响,且多线程安全
import java.lang.reflect.Constructor;
import java.util.Arrays;
public enum Day {
MONDAY("星期一", 1),
TUESDAY("星期二", 2),
WEDNESDAY("星期三", 3),
THURSDAY("星期四", 4),
FRIDAY("星期五", 5),
SATURDAY("星期六", 6),
SUNDAY("星期日", 7);//记住要用分号结束
private String desc;//文字描述
private Integer code; //对应的代码
/**
* 私有构造,防止被外部调用
*
* @param desc
*/
private Day(String desc,Integer code) {
this.desc = desc;
this.code = code;
}
/**
* 定义方法,返回描述,跟常规类的定义没区别
*
* @return
*/
public String getDesc() {
return desc;
}
/**
* 定义方法,返回代码,跟常规类的定义没区别
*
* @return
*/
public int getCode() {
return code;
}
public static void main(String[] args) throws Exception {
for (Day day : Day.values()) {
System.out.println("name:" + day.name() +
",desc:" + day.getDesc());
}
System.out.println(" is monday? " + isMonday(Day.MONDAY));
Day monday = Day.MONDAY;
Day tuesday = Day.MONDAY;
System.out.println("args = " + monday.equals(tuesday));
Constructor<Day> declaredConstructor = Day.class.getDeclaredConstructor(String.class,int.class,String.class,Integer.class);
// Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
//jad.exe反编译查看后 发现 枚举类,自带有
// private Day(String s, int i, String desc, Integer code)
// {
// super(s, i);
// this.desc = desc;
// this.code = code;
// }
declaredConstructor.setAccessible(true);
Day day = declaredConstructor.newInstance();
System.out.println("args = " + monday.equals(day));
}
static boolean isMonday(Day day){
if(Day.MONDAY.equals(day)){
return true;
}
return false;
}
}