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

单例模式实现方式有多种,例如懒汉模式(等用到时候再实例化),饿汉模式(类加载时就实例化)等,这里用饿汉模式方法实现,也就是类加载就实例化,单例模式应用场景有很多,比如一个应用有一套窗口化界面,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. Wordpress上传文件 “无法建立目录wp-content/uploads/2018/25。有没有上级目录的写权限?”

    可能的原因有两个: wp-content/uploads 文件夹权限所限制 解决方法:修改wp-content/uploads 文件夹权限,可以借助ftp等工具: wp_options表中upload ...

  2. 【基础】Attribute的妙用

    一.何为Attribute 下面是微软官方对Attribute的解释: 公共语言运行时允许你添加类似关键字的描述声明,叫做Attributes,它对程序中的元素进行标注,如类型.字段.方法和属性等.A ...

  3. C#获取存储过程的 Return返回值和Output输出参数值

    1.获取Return返回值  程序代码 //存储过程//Create PROCEDURE MYSQL//     @a int,//     @b int//AS//     return @a + ...

  4. Python小爬虫

                  网页解析器下载网址: http://www.crummy.com/software/BeautifulSoup/                               ...

  5. 基于SwiperJs的H5/移动端下拉刷新上拉加载更多的效果

    最早时,公司的H5项目中曾用过点击一个"加载更多"的DOM元素来实现分页的功能,后来又用过网上有人写的一个上拉加载更多的插件,那个插件是页面将要滚动到底部时就自动请求数据并插入到页 ...

  6. Winwos Server 2012发布ASP.NET MVC5 项目

    一.本文实验环境: Windows Server 2012 R2 Visual Studio 2015 项目为:ASP.NET MVC 5.0,使用的是SQL SERVER 2008 R2数据库 二. ...

  7. 熟悉的“if __name__ == '__main__':”究竟是啥?

    print(__name__) # 直接手动运行,打印"__main__",当做模块导入(别处import)时打印脚本名字即"name_main" if __n ...

  8. 小随笔:利用Shader给斯坦福兔子长毛和实现雪地效果

    0x00 前言 发现最近没有了写长篇大论的激情,可能是到了冬天了吧.所以这篇小文只是简单介绍下如何在Unity中利用shader很简单的实现雪地效果以及毛皮效果,当然虽然标题写在了一起,但其实这是俩事 ...

  9. ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证

    ASP.NET Identity除了提供基于Cookie的身份验证外,还提供了一些高级功能,如多次输入错误账户信息后会锁定用户禁止登录.集成第三方验证.账户的二次验证等,并且ASP.NET MVC的默 ...

  10. Pyhton编程(五)之基本数据类型-列表、元组、字典

    一:列表(list) 列表是由一系列按特定顺序排列的元素组成,可以创建包含字母表中的所有字母.数字.或中文的列表,也可以将任何东西加入列表中,其中的元素之间可以没有任何关系. 在Python中,用方括 ...