Java 序列化 之 单例模式

序列化相关文章:

Java 序列化 之 SerializableJava 序列化之 Externalizable

当我们使用Singleton模式时,应该是期望某个类的实例应该是唯一的,但如果该类是可序列化的,那么发序列化后还会是单例的吗?下面我们通过如下示例一来验证一下:

示例一

User 类

User 类是单例模式,使用的饿汉模式,在类加载的时候就创建对象实例。

public class User implements Serializable {    private static final long serialVersionUID = 3380014540967816490L;    private String userName;    private String password;    private static User user = new User(''zhangsan'', ''test'');        private User(String userName, String password) {        this.userName = userName;        this.password = password;    }    public static User getInstance() {        return user;    }    public String getUserName() {        return userName;    }    public String getPassword() {        return password;    }

小编是一个有着5年工作经验的java程序员,对于java,自己有做资料的整合,一个完整学习java的路线,学习资料和工具,相信这里有很多学习java的小伙伴,我创立了一个2000人学习扣群,479121291。每晚都有java的直播课程。无论是初级还是进阶的小伙伴小编我都欢迎!

Test 类

测试类,把 User 的单例实例序列化后在反序列化。

public class Test{    public static void main(String[] args) throws Exception {        File file = new File(''d:\\a.user'');        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));        oos.writeObject(User.getInstance());        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));        User user = (User) ois.readObject();        System.out.println(user);                if(user==User.getInstance()){            System.out.println(''同一个实例'');        }else{            System.out.println(''不同的实例'');        }    }}

执行结果如下:

输出的结果:User [userName=zhangsan, password=123456]不同的实例

通过结果可以看出,单例模式的饿汉模式也无法确保对象实例是单例的。

那么我们应该怎么解决这个问题呢?

readResolve() 方法

public class User implements Serializable {    private static final long serialVersionUID = 3380014540967816490L;    private String userName;    private String password;    private static User user = new User(''zhangsan'', ''123456'');    private User(String userName, String password) {        this.userName = userName;        this.password = password;    }    public static User getInstance() {        return user;    }    public String getUserName() {        return userName;    }    public String getPassword() {        return password;    }    public Object readResolve(){        return getInstance();    }    @Override    public String toString() {        return ''User [userName='' + userName + '', password='' + password + '']'';    }}

我们在 User 类中添加了一个 readResolve() 方法,该方法直接返回单例中的示例。然后在执行 Test.main() 方法执行结果如下:

输出的结果:User [userName=zhangsan, password=123456]不同的实例

无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。

猜你喜欢

转载自blog.csdn.net/java03_15/article/details/83541375