java 2进制 序列化_(二十一)、Java序列化与反序列化

一、什么是序列化与反序列化?

java 序列化是指把java 对象转换成字节序列的过程;

java 反序列化是指把字节序列恢复为java 对象的过程。

二、为什么要用序列化与反序列化

在 为什么要用序列化与反序列化 之前我们先了解一下对象序列化的两种用途:

1、把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;

2、在网络上传送对象的字节序列。

我们可以想象一下如果没有序列化之前,又是怎样一种情景呢?

举个栗子:

Web 服务器中的 Session 会话对象,当有10万用户并发访问,就有可能出现10万个 Session 对象,显然这种情况内存可能是吃不消的。

于是 Web 容器就会把一些 Session 先序列化,让他们离开内存空间,序列化到硬盘中,当需要调用时,再把保存在硬盘中的对象还原到内存中。

我们知道,当两个进程进行远程通信时,彼此可以发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。

同样的序列化与反序列化则实现了 进程通信间的对象传送,发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

初步总结:

Java 序列化和反序列化,其一,实现了数据的持久化,通过序列化可以把数据永久的保存在硬盘上;其二,利用序列化实现远程通信,即在网络上传递对象的字节序列。

三、如何实现序列化与反序列化?

1、JDK类库中序列化API

使用到JDK中关键类 ObjectOutputStream(对象输出流) 和ObjectInputStream(对象输入流)

ObjectOutputStream 类中:通过使用 writeObject(Object object) 方法,将对象以二进制格式进行写入。

ObjectInputStream 类中:通过使用 readObject()方法,从输入流中读取二进制流,转换成对象。

2、目标对象实现Serizalizable接口

我们创建一个 User 类,实现 Serializable 接口,并生成一个版本号 :

public class User implementsSerializable{private static final long serialVersionUID = 3604972003323896788L;private transient intage;privateString name;privateString sex;public intgetAge(){returnage;

}publicString getName(){returnname;

}publicString getSex(){returnsex;

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

}public voidsetName(String name){this.name =name;

}public voidsetSex(String sex){this.sex =sex;

}

}

首先:

a. Serializable接口的作用只是用来标识我们这个类是需要进行序列化,并且Serializable接口中并没有提供任何方法。

b. SerialVersionUID序列化版本号的作用是用来区分我们所编写的类的版本,用于判断反序列化时类的版本是否一致,如果不一致会出现版本不一致异常。

c. transient关键字,主要用来忽略我们不希望进行序列化的变量。

由于第一种形式太不常见,直接来看第二种实现Serializable接口的写入方式

定义一个Person类,实现Serializable接口

public class Person implementsSerializable{private static final long serialVersionUID = -5809452578272945389L;private intage;privateString name;privateString sex;

get...

set...

}

序列化和反序列化Person类对象

importjava.io.FileInputStream;importjava.io.File;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.text.MessageFormat;/*** Description: 测试对象的序列化和反序列*/

public classtest{public static void main(String[] args) throwsException {

SerializePerson();//序列化Person对象

Person p = DeserializePerson();//反序列Perons对象

System.out.println(MessageFormat.format("name={0},age={1},sex={2}",

p.getName(), p.getAge(), p.getSex()));

}/*** Description: 序列化Person对象*/

private static void SerializePerson() throwsFileNotFoundException, IOException{

Person person= newPerson();

person.setName("leslie");

person.setAge(22);

person.setSex("男");//ObjectOutputStream 对象输出流//将Person对象存储到硬盘的Person.txt文件中,完成对Person对象的序列化操作

ObjectOutputStream oo = new ObjectOutputStream(newFileOutputStream(new File("/home/leslie/Desktop/sdfsd/测试代码/Person.txt")));

oo.writeObject(person);

System.out.println("Person对象序列化成功!");

oo.close();

}/*** Description: 反序列Perons对象*/

private static Person DeserializePerson() throwsException, IOException{//ObjectInputStream 对象输流入//读取存储在硬盘中的Person.txt文件,完成对Person对象的反序列化

ObjectInputStream ois = new ObjectInputStream(newFileInputStream(new File("/home/leslie/Desktop/sdfsd/测试代码/Person.txt")));

Person person=(Person) ois.readObject();

System.out.println("Person对象反序列化成功!");returnperson;

}

}

运行结果

8fd3b006ff9f2fef8d5dd3bbbf01da30.png

61747a9f15ce205467a5b65f8f4aab0f.png

疑问:Person 实体中的 serialVersionUID 是个什么鬼?

答:序列化版本号,取值是 Java 运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的 serialVersionUID 的取值有可能也会发生变化。。

继承程序帮我们自动生成,那为何还要去定义该属性?

序列化和反序列化就是通过对比其 SerialversionUID 来进行的,我们修改一个实现 Serializable 接口的实体类,重新编译后,显然程序会重新会生成新值,那么一旦SerialversionUID 跟之前不匹配,反序列化就无法成功。

在实际的生产环境中,我们可能会建一系列的中间 Object 来反序列化我们的 pojo,为了解决这个问题,我们就需要在实体类中自定义 SerialversionUID,就像上方示例,不管我们序列化之后如何更改我们的 实体(不删除原有字段),最终都可以反序列化成功。。

四、总结

Java 中对象的序列化就是将对象转换成二进制序列,反序列化则是将二进制序列转换成对象。

采用Java序列化与反序列化技术:

一是可以实现数据的持久化,在MVC模式中很是有用;

二是可以对象数据的远程通信。

Java 实现序列化的多种方式

1、首先需要使用到工具类 ObjectInputStream 和ObjectOutputStream 两个IO类

2、实现 Serializable 接口

3、实现 Externalizable 接口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值