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 ...
随机推荐
- 数据可视化之 图表篇(五) PowerBI图表不够炫酷?来看看这个
现在这个大数据时代,每时每刻.各行各业都在产生多种多样的海量数据,如何简单高效的来理解.挖掘这些数据,发现背后的见解就非常重要. 本文介绍这个图表就可以帮你快速发现海量数据背后的见解,微软研究院打造的 ...
- Django框架09 /ajax、crsf、settings导入
Django框架09 /ajax.crsf.settings导入 目录 Django框架09 /ajax.crsf.settings导入 1. ajax概述 2. ajax应用 3. ajax上传文件 ...
- 用Canvas定时显示摄像头捕获的画像(HTML5)
需要实现一个功能,大意嘛,就是标题写的那个意思.虽然用户只要求在微信中实现即可,也就是可以用JSSDK.但是前端小哥哥脑袋一根筋,就想用原生的H5和JS实现. 网上铺天盖地的资料,可惜没有一个是可以用 ...
- Mysql数据库搭建集群---实现主从复制,读写分离
参考博客:https://blog.csdn.net/xlgen157387/article/details/51331244 A. 准备:多台服务器,且都可以互相随意访问root用户,都可以随意进 ...
- MYSQL JSON字段操作
create CREATE TABLE t_test ( salary_data json NULL COMMENT 'JSON类型字段' ); -- insert INSERT INTO t_tes ...
- GPO - General GPO Settings(3)
WMI filtering Setting - Differentiating Installation Between Operations and Architecture. WMI SQL Ge ...
- C++语法小记---类型检测
类型检测 C++使用typeid关键字进行类型检查 不同的编译器使用typeid返回的类型名称不严格一致,需要特别注意 也可以使用虚函数,返回各自的类型名 如果typeid的操作数不是类类型(类指针也 ...
- 想进大厂?字节跳动等独角兽公司都在招募Python工程师!(Python就是第一语言)
在本文章中,作者通过自身经历,力求客观的谈谈个人选择学习Python的动机,以及独角兽公司对Python工程师的要求及薪资. 从目前各种迹象(企业招聘,语言排名等)看来Python相对Java应该是暂 ...
- 分布式ID生成服务,真的有必要搞一个
目录 阐述背景 Leaf snowflake 模式介绍 Leaf segment 模式介绍 Leaf 改造支持RPC 阐述背景 不吹嘘,不夸张,项目中用到ID生成的场景确实挺多.比如业务要做幂等的时候 ...
- JavaScript运算符与流程控制
JavaScript运算符与流程控制 运算符 赋值运算符 使用=进行变量或常量的赋值. <script> let username = "YunYa"; < ...