单例模式:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

单例模式实现方式有多种,例如懒汉模式(等用到时候再实例化),饿汉模式(类加载时就实例化)等,这里用饿汉模式方法实现,也就是类加载就实例化,单例模式应用场景有很多,比如一个应用有一套窗口化界面,Servlet中只有一个实例,应用很广泛

package com.test;

public class Singleton {

    private Singleton() {}
private static final Singleton INSTANCE = new Singleton(); //饿汉模式 public static Singleton getInstance() {
return INSTANCE;
}
}

单例模式基本上是每个java程序员都知道的,effective java第一章讲的是对象创建与销毁,看到单例模式在序列化中会失效时,这个是我之前所不知道的,于是查阅资料,并亲自验证一下,过程很简单,将上面的单例类实现Serializable接口

package com.test;

import java.io.Serializable;

public class Singleton implements Serializable{

    /**
* @Fields serialVersionUID : TODO
*/
private static final long serialVersionUID = -6367362518368424353L; private Singleton() {}
private static final Singleton INSTANCE = new Singleton(); public static Singleton getInstance() {
return INSTANCE;
}
}

是时候来验证一下了

package com.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; public class Test {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
Singleton before = Singleton.getInstance(); //序列化,将对象写入到文件
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\objectFile"));
oos.writeObject(before);
oos.close(); //反序列化,读取文件,还原成对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\objectFile"));
Singleton after = (Singleton) ois.readObject();
ois.close(); //验证结果
System.out.println(before == after);
}
}

输出:false

这说明一旦对象被序列化了,就破坏了单例模式,因为重新读取的对象已经不是之前的对象,它重新生成了一个!

那么问题来了,如何解决单例模式与序列化的矛盾?

effective给出了解决方法,只需添加一个readResolve方法,即

package com.test;

import java.io.Serializable;

public class Singleton implements Serializable{

    /**
* @Fields serialVersionUID : TODO
*/
private static final long serialVersionUID = -6367362518368424353L; private Singleton() {}
private static final Singleton INSTANCE = new Singleton(); public static Singleton getInstance() {
return INSTANCE;
} private Object readResolve() {
return INSTANCE;
}
}

再运行一下之前的测试类,发现结果又变成true了,说明反序列化单例模式没有被破坏!关于其中的原理可以参阅这篇博客 http://www.hollischuang.com/archives/1144

终极解决方法,枚举类!

使用起来极其简单,只需要

package com.test;

import java.io.Serializable;

public enum Singleton implements Serializable{
INSTANCE;
}

然后再测试一下

package com.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; public class Test {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
Singleton before = Singleton.INSTANCE; //序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\objectFile"));
oos.writeObject(before);
oos.close(); //反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\objectFile"));
Singleton after = (Singleton) ois.readObject();
ois.close(); //验证结果
System.out.println(before == after);
}
}

输出结果为true

effective java笔记之单例模式与序列化的更多相关文章

  1. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  2. Effective java笔记(二),所有对象的通用方法

    Object类的所有非final方法(equals.hashCode.toString.clone.finalize)都要遵守通用约定(general contract),否则其它依赖于这些约定的类( ...

  3. effective java笔记之java服务提供者框架

    博主是一名苦逼的大四实习生,现在java从业人员越来越多,面对的竞争越来越大,还没走出校园,就TM可能面临失业,而且对那些增删改查的业务毫无兴趣,于是决定提升自己,在实习期间的时间还是很充裕的,期间自 ...

  4. Effective java笔记(十),序列化

    将一个对象编码成字节流称作将该对象「序列化」.相反,从字节流编码中重新构建对象被称作「反序列化」.一旦对象被「序列化」后,它的编码就可以从一台虚拟机传递到另一台虚拟机,或被存储到磁盘上,供以后「反序列 ...

  5. Effective java笔记(一),创建与销毁对象

    1.考虑用静态工厂方法代替构造器 类的一个实例,通常使用类的公有的构造方法获取.也可以为类提供一个公有的静态工厂方法(不是设计模式中的工厂模式)来返回类的一个实例.例如: //将boolean类型转换 ...

  6. Effective java笔记(六),方法

    38.检查参数的有效性 绝大多数方法和构造器对于传递给它们的参数值都会有限制.如,对象引用不能为null,数组索引有范围限制等.应该在文档中指明所有这些限制,并在方法的开头处检查参数,以强制施加这些限 ...

  7. effective java 笔记1--序言

    一.序言 程序设计的几条基本原则: 1.清晰性和简洁性最为重要,模块的用户永远也不应该被模块的行为所迷惑,所以写良好的注释是必需的. 2.模块要竟可能小,但也不能太小,好一个深奥的哲学问题. 3.代码 ...

  8. Effective Java笔记

    chapter 1 java支持四种类型:interface,class,array,primitive(基本类型) chapter 2 创建对象方式: ①构造器 ②静态工厂方法代替构造器:名称可以按 ...

  9. Effective Java 笔记

    1. 静态工厂 静态工厂的第 5 个优点是,在编写包含该方法的类时,返回的对象的类不需要存在.他的意思是面向接口编程??就是说我们只需知道接口,具体实现类是否存在没有关系?? 只提供静态工厂方法的主要 ...

随机推荐

  1. C#生成缩略图源码

    先看调用的方法: ).ToUpper())                {                    case "JPG":                      ...

  2. matplotlib删除x轴

    组内有个同事,有个奇怪的需求需要matplotlib删除x轴 效果图如下:

  3. python之socket模块

    UDP client #!/usr/bin/env python2.7 #-*-coding:utf-8 -*- import socket s=socket.socket(socket.AF_INE ...

  4. VPN连接机器不再输入密码以及Pin码方法

    连接机器不输入密码 #!/usr/bin/env expect   spawn ssh guosong@xx_ip; expect "*password*"; send  &quo ...

  5. raid卡MegaCli工具使用说明

    一.DELL&IBMMegaCli -AdpAllInfo -aALL —看配置项 #检查raid级别MegaCli -LDInfo -Lall -aALL | grep 'RAID Leve ...

  6. 深度学习的异构加速技术(一):AI 需要一个多大的“心脏”?

    欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:kevinxiaoyu,高级研究员,隶属腾讯TEG-架构平台部,主要研究方向为深度学习异构计算与硬件加速.FPGA云.高速视觉感知等方向 ...

  7. 【Java】单词倒序输出

    如何将一段单词倒序输出?把"Hello Java Hello China"变成"China Hello Java Hello"? 看起来好像很简单,只需要把字符 ...

  8. IIFE(立即执行函数表达式)

    我们经常会看到这样的写法: ;(fuction () { // do something })() 这就是一个简单的IIFE(立即执行函数表达式,immediately-invoked functio ...

  9. RPC是什么

    RPC是什么? 通俗的讲就是,调用远程计算机上的服务,就像调用本地服务一样.通常包含传输协议和编码协议. RPC可以基于HTTP或TCP协议,但基于HTTP协议的RPC性能却不如基于TCP协议的RPC ...

  10. WeChat 隐私政策

    隐私政策 本应用尊重并保护所有使用服务用户的个人隐私权.为了给您提供更准确.更有个性化的服务,本应用会按照本隐私权政策的规定使用和披露您的个人信息.但本应用将以高度的勤勉.审慎义务对待这些信息.除本隐 ...