19、Java 序列化
1、序列化的概念,意义以及使用场景
序列化:
将对象写入到IO流中,也就是把Java对象转换为字节序列的过程
反序列化:
从IO流中恢复对象*,也就是把字节序列恢复为Java对象的过程
意义:
序列化机制允许将实现序列化的Java对象转换位字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。
使用场景:
(1)永久性保存对象,保存对象的字节序列到本地文件或者数据库中;、
(2)通过序列化以字节流的形式使对象在网络中进行传递和接收;
(3)通过序列化在进程间传递对象;
所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:程序创建的每个JavaBean类都实现Serializeable接口。
2、好处
其实好处是根据使用场景来的;
(1)实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上
(2)利用序列化实现远程通信,即在网络上传送对象的字节序列。
3、Java中实现序列化的俩种方式
3.1 使用Serializable接口实现序列化
定义一个对象类 Student
package com.example.main; import java.io.*; /**
* @author lin
* @version 1.0
* @date 2020/7/11 22:04
* @Description TODO
*/
public class Student implements Serializable {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 1111013L;
private String name;
private String gender; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} @Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
'}';
} /**
* 序列化方法
*/
private static void serializeStudent() {
try {
Student student = new Student();
student.setName("张无忌");
student.setGender("男");
// 对象 序列化 到 文件中
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D://student"));
os.writeObject(student);
os.close();
System.out.println("序列化完成");
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 反序列化方法
*/
private static void deSerializeStudent() {
try {
ObjectInputStream is = new ObjectInputStream(new FileInputStream("D://student"));
Student stu = (Student) is.readObject();
System.out.println("反序列化成功:" + stu.toString());
is.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
serializeStudent();
deSerializeStudent();
}
}
运行结果如下:
序列化完成
反序列化成功:Student{name='张无忌', gender='男'}
3.2 使用Externalizable接口实现序列化
定义一个Person类
package com.example.main; import java.io.*; /**
* @author lin
* @version 1.0
* @date 2020/7/11 22:18
* @Description TODO
*/
public class Person implements Externalizable {
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;
} public Person(String name, int age) {
this.name = name;
this.age = age;
} public Person() {
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
} @Override
public void writeExternal(ObjectOutput out) throws IOException {
//将name反转后写入二进制流
StringBuffer reverse = new StringBuffer(name).reverse();
System.out.println(reverse.toString());
out.writeObject(reverse);
out.writeInt(age);
} @Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
//将读取的字符串反转后赋值给name实例变量
this.name = ((StringBuffer) in.readObject()).reverse().toString();
System.out.println(name);
this.age = in.readInt();
} public static void main(String[] args) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Person.txt"));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Person.txt"));
oos.writeObject(new Person("brady", 23));
Person ep = (Person) ois.readObject();
System.out.println(ep);
}
}
运行结果如下:
ydarb
brady
Person{name='brady', age=23}
两种序列化对比
| 实现Serializable接口 | 实现Externalizable接口 |
|---|---|
| 系统自动存储必要的信息 | 程序员决定存储哪些信息 |
| Java内建支持,易于实现,只需要实现该接口即可,无需任何代码支持 | 必须实现接口内的两个方法 |
| 性能略差 | 性能略好 |
虽然Externalizable接口带来了一定的性能提升,但变成复杂度也提高了,所以一般通过实现Serializable接口进行序列化。
4、分析java序列化机制
4.1 serialVersionUID的作用
其目的是序列化对象版本控制,有关各版本反序列化时是否兼容。如果在新版本中这个值修改了,新版本就不兼容旧版本,反序列化时会抛出InvalidClassException异常。如果修改较小,比如仅仅是增加了一个属性,我们希望向下兼容,老版本的数据都能保留,那就不用修改;如果我们删除了一个属性,或者更改了类的继承关系,必然不兼容旧数据,这时就应该手动更新版本号,即SerialVersionUid。
4.2 静态变量的序列化
需要说一下,静态变量不会被序列化。因为静态变量在全局区,本来流里面就没有写入静态变量,我打印静态变量当然会去全局区查找,当我write read 同时使用时,内存中的静态变量变了,所以打印出来的也变了。
自行可以测试一下. 将变量 增加 static 静态变量
结果会出现两种情况:
(1)反序列输出的静态变量值没有变化:说明静态变量被序列化了。
(2)反序列输出的静态变量值变化了:说明静态变量没有被序列化了。
4.3 Transient 关键字作用
Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
将Student类中的gender修改为 :
private transient String gender;
再次运行结果如下:
序列化完成
反序列化成功:Student{name='张无忌', gender='null'}
5、总结
java提供的序列化机制还是比较常用的,也是比较简单的。
1. 所有需要网络传输的对象都需要实现序列化接口,通过建议所有的javaBean都实现Serializable接口。
2. 对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化。
3. 如果想让某个变量不被序列化,使用transient修饰。
4. 序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。
5. 反序列化时必须有序列化对象的class文件。
6. 当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。
7. 单例类序列化,需要重写readResolve()方法;否则会破坏单例原则。
8. 同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化。
9. 建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级。
发哥讲
如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~
● 扫码关注公众号
19、Java 序列化的更多相关文章
- Java 序列化Serializable详解
Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...
- 各种Java序列化性能比较
转载:http://www.jdon.com/concurrent/serialization.html 这里比较Java对象序列化 XML JSON Kryo POF等序列化性能比较. 很多人以 ...
- Java序列化的几种方式以及序列化的作用
Java序列化的几种方式以及序列化的作用 本文着重讲解一下Java序列化的相关内容. 如果对Java序列化感兴趣的同学可以研究一下. 一.Java序列化的作用 有的时候我们想要把一个Java对象 ...
- java序列化---转
Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是 ...
- Java 序列化 序列化与单例模式 [ 转载 ]
Java 序列化 序列化与单例模式 [ 转载 ] @author Hollis 本文将通过实例+阅读Java源码的方式介绍序列化是如何破坏单例模式的,以及如何避免序列化对单例的破坏. 单例模式,是设计 ...
- Protocol Buffer序列化对比Java序列化.
初识 Protocol Buff是谷歌推出的一种序列化协议. 而Java序列化协议也是一种协议. 两者的目的是, 将对象序列化成字节数组, 或者说是二进制数据, 那么他们之间有什么差异呢. proto ...
- Java序列化框架性能比較
博客: http://colobu.com jvm-serializers提供了一个非常好的比較各种Java序列化的的測试套件. 它罗列了各种序列化框架. 能够自己主动生成測试报告. 我在AWS c3 ...
- 深入学习 Java 序列化
前言 对于Java的序列化,一直只知道只需要实现Serializbale这个接口就可以了,具体内部实现一直不是很了解,正好这次在重复造RPC的轮子的时候涉及到序列化问题,就抽时间看了下 Java序列化 ...
- 浅析若干Java序列化工具【转】
在Java中socket传输数据时,数据类型往往比较难选择.可能要考虑带宽.跨语言.版本的兼容等问题.比较常见的做法有: 采用java对象的序列化和反序列化 把对象包装成JSON字符串传输 Googl ...
随机推荐
- 数据可视化实例(五): 气泡图(matplotlib,pandas)
https://datawhalechina.github.io/pms50/#/chapter2/chapter2 关联 (Correlation) 关联图表用于可视化2个或更多变量之间的关系. 也 ...
- python之爬虫(四)之 Requests库的基本使用
什么是Requests Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库如果你看过上篇文章关于urllib库的使用,你会发现,其 ...
- MySQL索引——总结篇
MySQL索引 MySQL索引 数据库的三范式,反模式 零碎知识 索引 索引原理 B Tree索引 B+Tree索引 B Tree 与 B+Tree的比较 聚集索引和辅助索引 聚集索引的注意事项 索引 ...
- 「美团面试系列」面试加分项,这样说你会JVM,面试官还能问什么
Java性能调优都是老生常谈的问题,特别当“糙快猛”的开发模式大行其道时,随着系统访问量的增加.代码的臃肿,各种性能问题便会层出不穷. 比如,下面这些典型的性能问题,你肯定或多或少都遇到过: 在进行性 ...
- 技术干货:Ceph搭建硬件建议详解
Ceph是专为在商品硬件上运行而设计的,这使得构建和维护超大规模的数据集群在经济上是可行的.当规划出你的集群硬件时,你需要平衡一些考虑因素,包括故障域和潜在的性能问题.硬件规划应该包括将Ceph守护进 ...
- list基本使用
list和vector的用法基本相同,区别如下: list可以头尾插入和删除,效率一样,vector只有尾部插入和删除效率才高,头部操作效率很低 list的排序有专有的接口,不能使用全局的接口,原因是 ...
- SQL数据多条转单条(CONCAT_WS)
一.concat()函数可以连接一个或者多个字符串 concat(str1,str2,…) 返回结果为连接参数产生的字符串.如有任何一个参数为NULL ,则返回值为 NULL. select conc ...
- 关联吸纳的remote首次push报错rejected
F:\abb-iot\DmsAPI\DmsAPI (master -> origin) λ git push --set-upstream github master To github.com ...
- .NET Core 发布到 IIS
①右键项目->属性 将生成配置为Release ②右键项目->重新生成 ③提示生成成功后,右键项目->发布 点击新建,-> 这一步可以选择文件系统, 也可以选择IIS FT 以 ...
- vue 修改路由
直接放代码: this.$router.push({ path: "/login" });