一、readResolve()法
首先构造一个可序列化的单例模式类
public class User implements Serializable {
private static final User instance=new User();
public String name;
public int age;
private User()
{
name="Sean";
age=23;
}
public static User getInstance()
{
return instance;
}
}
利用反序列化实施破解工作
public class TestSelializable {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
User a=User.getInstance();
ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream("C:/user.txt"));
os.writeObject(a);
os.flush(); //利用管道将实例a序列化输出到文件user.txt中
os.close();
ObjectInputStream is=new ObjectInputStream(new FileInputStream("C:/user.txt"));
User b=(User) is.readObject(); //利用管道将user.txt中的实例反序列化输入进来作为对象b
is.close(); //这实际上就等于重新生成了另一个单例对象
b.name="Moon";
b.age=31;
System.out.println("a's name:"+a.name+" "+"a's age:"+a.age);
System.out.println("b's name:"+b.name+" "+"b's age:"+b.age);
//输出对象a、b的信息,不同则证明反序列化破解了单例模式
}
}
运行结果:
a's name:Sean a's age:23
b's name:Moon b's age:31
这就证明了单例模式遭到了反序列化的破坏
解决办法:
public class User implements Serializable {
private static final User instance=new User();
public String name;
public int age;
private User()
{
name="Sean";
age=23;
}
public static User getInstance()
{
return instance;
}
//在单例类中添加readResolve()方法
//每当JVM从文件中向内存反序列化新建一个对象时就对调用该方法,加入适当操作即可防止反序列化
private Object readResolve()
{
return instance;
}
}
再看修改后测试程序的运行结果:
a's name:Moon a's age:31
b's name:Moon b's age:31
a、b对象输出信息一致说明readResolve()防止反序列化破解成功
二、枚举法
先构造一个可序列化的单例模式枚举类
public enum UserEnum implements Serializable {
instance;
public String name="Sean";
public int age=23;
}
利用类似的反序列化实施破解
public class TestSelializable {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
UserEnum a=UserEnum.instance;
ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream("C:/userenum.txt"));
os.writeObject(a);
os.flush(); //利用管道将枚举实例a序列化输出到文件userenum.txt中
os.close();
ObjectInputStream is=new ObjectInputStream(new FileInputStream("C:/userenum.txt"));
UserEnum b=(UserEnum) is.readObject(); //利用管道将user.txt中的枚举实例反序列化输入进来作为枚举实例b
is.close();
b.name="Moon";
b.age=31;
System.out.println("a's name:"+a.name+" "+"a's age:"+a.age);
System.out.println("b's name:"+b.name+" "+"b's age:"+b.age);
//输出枚举对象a、b的信息,不同则证明序列化破解了枚举单例模式
}
}
运行结果:
a's name:Moon a's age:31
b's name:Moon b's age:31
枚举对象a、b输出相同的信息说明枚举天生就有防止反序列化破解的能力,可以放心使用