学习JAVA的时候,特别是涉及到网络编程时,我们时常让我们的实体类实现一个接口

public class Entity implements Serializable{

}

这样子我们可以通过输入输出流ObjectOutputStream和ObjectInputStream写入或读取该对象。所以,简单来说,序列化就是把对象转换为字节数据流,反序列化就是把字节序列流转成相应的Java对象。使用序列化的最常用的两个场景:

1、需要把对象信息存储到磁盘文件中的时候,比如大量用户登录的Session信息

2、需要把对象信息通过网络传送的时候,需要传送字节流

实现java.io.Serializable接口之后,编辑器会给出警告,让你给出一个属性的定义:

private static final long serialVersionUID = 1L;

我们可以简单的认为,这是一个“类版本”的表示,不同的编辑器可能会对同一个类给出不同的值,类文件的细小改动也可能会产生不同的值,因为这个值在类变更之后起到了代码兼容的作用,一般规则如下:

1、两个不同版本的类,如果serialVersionUID相同,则说明反序列化兼容,以现有版本为模板反序列化

2、两个不同版本的类,如果serialVersionUID不同,说明反序列化不兼容,反序列化会失败

因此,我们的开发过程中,建议显示定义该值,并给以明确的定义,以方便兼容性判断。

下面代码示例,首先定义一个可序列化的实体对象:

package com.minlz.serialize;

import java.io.Serializable;

/**
 *  @author minliangzhi
 *  @date 2016年8月30日
 */
public class Person implements Serializable {

    private static final long serialVersionUID = 20160830001L;

    private String name;

    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

然后给出一个序列化和反序列化的方法:

    public static void main(String[] args) throws Exception {
        Person p1 = new Person();
        p1.setName("Bruce Min");
        p1.setAge(25);
        System.out.println("p1: " + p1.toString());
        /** 序列化 */
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream objOut = new ObjectOutputStream(byteOut);
        objOut.writeObject(p1);

        /** 反序列化 */
        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream objIn = new ObjectInputStream(byteIn);
        Person p2 = (Person)objIn.readObject();
        System.out.println("p2: " + p2.toString());
    }

显示的结果是:

p1: Person [name=Bruce Min, age=25]
p2: Person [name=Bruce Min, age=25]

通过上面的实例,大概对序列化和反序列化进行了介绍,需要注意的是,通过反序列获得对象不是原来的对象,即不满足“==”为真的情况,因为,如果我们是序列化一个单例实例的话,就会违反了单例模式的规定(虽然隐藏了单例的构造函数,但是JVM可以通过特殊手段,如反射来构造出对象)。实例如下:

单例类:

package com.minlz.serialize;

import java.io.Serializable;

/**
 *  @author minliangzhi
 *  @date 2016年8月30日
 */
public class Singleton implements Serializable {
    private static final long serialVersionUID = 1L;
    private static Singleton singleton;

    private Singleton() {

    }

    public synchronized static Singleton getInstance() {
        if(null == singleton) {
            singleton = new Singleton();
        }

        return singleton;
    }
}

序列化和反序列化的代码:

    public static void main(String[] args) throws Exception {
        Singleton s1 = Singleton.getInstance();

        System.out.println(s1);
        /** 序列化 */
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream objOut = new ObjectOutputStream(byteOut);
        objOut.writeObject(s1);

        /** 反序列化 */
        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream objIn = new ObjectInputStream(byteIn);
        Singleton s2 = (Singleton)objIn.readObject();
        System.out.println(s2);
  }

测试结果:

com.minlz.serialize.Singleton@47abfd68
com.minlz.serialize.Singleton@514ae5cd

可以容易看出来,两个对象不是同一个对象,解决方法是什么呢?

我们在Singleton类中增加一个方法:

    public Object readResolve(){
        return getInstance();
    }

发现测试结果是:

com.minlz.serialize.Singleton@8523ca2
com.minlz.serialize.Singleton@8523ca2

两个对象一致了,所以当面临单例模式实例化的时候,需要实现public Object readResolve()方法,并返回单例实例,就能实现序列化和反序列化对象一致。

Java序列化、反序列化和单例模式的更多相关文章

  1. java序列化反序列化深入探究

    When---什么时候需要序列化和反序列化: 简单的写一个hello world程序,用不到序列化和反序列化.写一个排序算法也用不到序列化和反序列化.但是当你想要将一个对象进行持久化写入文件,或者你想 ...

  2. java序列化反序列化深入探究(转)

    When---什么时候需要序列化和反序列化: 简单的写一个hello world程序,用不到序列化和反序列化.写一个排序算法也用不到序列化和反序列化.但是当你想要将一个对象进行持久化写入文件,或者你想 ...

  3. 初尝Java序列化/反序列化对象

    看个类: package com.wjy.bytes; import java.io.Serializable; public class ObjTest implements Serializabl ...

  4. java序列化/反序列化之xstream、protobuf、protostuff 的比较与使用例子

    目录 背景 测试 环境 工具 说明 结果 结论 xstream简单教程 准备 代码 protobuf简单教程 快速入门 下载.exe编译器 编写.proto文件 利用编译器编译.proto文件生成ja ...

  5. Java序列化反序列化对象流ObjectInputStream、ObjectOutputStream

    使用Person类作为Object进行示范 注意:Object要能被写入流需要实现Serializable接口 存储的文件后缀名为.ser 示范Person类 import java.io.Seria ...

  6. Java——序列化 反序列化

    记录一下: 先粘两个比较繁琐的方法: put: public void putSerializableObject(String key, Object value, int expireTime) ...

  7. Java 序列化 反序列化 历史版本处理

    直接引用  http://www.cnblogs.com/xdp-gacl/p/3777987.html

  8. Java 序列化 序列化与单例模式 [ 转载 ]

    Java 序列化 序列化与单例模式 [ 转载 ] @author Hollis 本文将通过实例+阅读Java源码的方式介绍序列化是如何破坏单例模式的,以及如何避免序列化对单例的破坏. 单例模式,是设计 ...

  9. Serializable详解(1):代码验证Java序列化与反序列化

    说明:本文为Serializable详解(1),最后两段内容在翻译上出现歧义(暂时未翻译),将在后续的Serializable(2)文中补充. 介绍:本文根据JDK英文文档翻译而成,本译文并非完全按照 ...

  10. Java 序列化与反序列化

    1.什么是序列化?为什么要序列化? Java 序列化就是指将对象转换为字节序列的过程,而反序列化则是只将字节序列转换成目标对象的过程. 我们都知道,在进行浏览器访问的时候,我们看到的文本.图片.音频. ...

随机推荐

  1. Linux下查看磁盘与目录的容量——df、du

    df:列出文件系统的整体磁盘使用量: du:评估文件系统的磁盘使用量(常用于评估目录所占容量) df参数: -a:列出所有的文件系统,包括系统特有的/proc等文件系统 -k:以KB的容量显示各文件系 ...

  2. 企业号查询部门id(改版后)

    1.搜索部门,输入"名称" 2.在后面可以查到部门ID

  3. markdown简介

    欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接 ...

  4. 正确解读free -m

    如下显示free是显示的当前内存的使用,-m的意思是M字节来显示内容.我们来一起看看. $ free -m total used free shared buffers cachedMem: 1002 ...

  5. 如何做JS 单体模式的设计---->>js设计模式<<-------单体模式

    1. 单体模式是js中最基本 单最有用的模式之一,非常常用. 单体模式的基本结构如下: var Person = { name: 'lilu', age:', sayHi: function(){ a ...

  6. 将数据导入Excel

    /** * 查询未打印订单 * @param req * @param sort * @param order * @param rows * @param page * @return */ pub ...

  7. UML大战需求分析——阅读笔记04

    读<UML大战需求分析>有感04 开发某系统的重要前提是: 这个系统有谁在用? 这些人通过这个系统能做什么事? 一般搞清楚这件事,再画个业务流程图,就能条例清楚的表达系统的需求了.作为一个 ...

  8. 两个单选按钮(一个是,一个否 ),一个div层,实现点击隐藏,显示div

    <script type="text/javascript"> function diva(){ document.getElementById('div1').sty ...

  9. ElasticSearch性能优化官方建议

    ES 手册 如何提高ES的性能 不要返回较大的结果集 ES是设计成一个搜索引擎的,只擅长返回匹配查询较少文档,如果需要返回非常多的文档需要使用Scroll. 避免稀疏 因为ES是基于Lucene来索引 ...

  10. C#设置IE代理及遇到问题的解决方案

    起初使用的方法是修改完一次代理之后就不能继续修改,需要重新启动一次进程才可以,最初代码是: private void ShowProxyInfo() { if (!GetProxyStatus()) ...