教你彻底学会Java序列化和反序列化

Hollis

共 7734字,需浏览 16分钟

 ·

2020-09-24 08:32


Java序列化是什么?

Java序列化是指把Java对象转换为字节序列的过程,Java反序列化是指把字节序列恢复为Java对象的过程。反序列化:客户端重文件,或者网络中获取到文件以后,在内存中重构对象。序列化:对象序列化的最重要的作用是传递和保存对象的时候,保证对象的完整性和可传递性。方便字节可以在网络上传输以及保存在本地文件。


为什么需要序列化和反序列化


实现分布式

核心在于RMI,可以利用对象序列化运行远程主机上的服务,实现运行的时候,就像在本地上运行Java对象一样。



实现递归保存对象

进行序列化的时候,单单并不是保存一个对象,而是递归的保存一整个对象序列,即递归保存,通过反序列化,可以递归的得到一整个对象序列。


序列信息可以永久保存

用于序列化的信息,可以永久保存为文件,或者保存在数据库中,在使用的时候,再次随时恢复到内存中,实现内存中的类的信息可以永久的保存。


数据格式统一

比照Linux的一切皆文件的思想,同时Java也是这样的思想,让数据格式尽可能的统一,让对象,文件,数据,等等许许多多不同的格式,都让其统一,以及保存。实现数据可以完整的传输和保存。然后进行反序列化还原,即,对象还是对象,文件还是文件。


实现Java序列化和反序列化

要进行反序列化需要实现一个接口。即 Serializabei接口。代码如下 需要转化的类

package common.lang;
import java.io.Serializable;
import org.apache.commons.lang3.builder.ToStringBuilder;import org.apache.commons.lang3.builder.ToStringStyle;
public class User1 implements Serializable{
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 new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) .append("name", name) .append("age", age) .toString(); }}

进行序列化,以及反序列化

package common.lang;
import java.io.File;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 SerializableDemo1 {
public static void main(String[] args) throws Exception, IOException { //初始化对象 User1 user = new User1(); user.setName("yaomy"); user.setAge(23); System.out.println(user); //序列化对象到文件中 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("template")); oos.writeObject(user); oos.close(); //反序列化 File file = new File("template"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); User1 newUser = (User1)ois.readObject(); System.out.println(newUser.toString()); }}


另一个序列化接口 Externalizable

继续实现Externalizable接口

package common.lang;
import java.io.Externalizable;import java.io.IOException;import java.io.ObjectInput;import java.io.ObjectOutput;
import org.apache.commons.lang3.builder.ToStringBuilder;import org.apache.commons.lang3.builder.ToStringStyle;
public class User1 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; } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) .append("name", name) .append("age", age) .toString(); } @Override public void writeExternal(ObjectOutput out) throws IOException { // TODO Auto-generated method stub } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // TODO Auto-generated method stub }}

进行序列化以及反序列化

package common.lang;
import java.io.File;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 SerializableDemo1 {
public static void main(String[] args) throws Exception, IOException { //初始化对象 User1 user = new User1(); user.setName("yaomy"); user.setAge(23); System.out.println(user); //序列化对象到文件中 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("template")); oos.writeObject(user); oos.close(); //反序列化 File file = new File("template"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); User1 newUser = (User1)ois.readObject(); System.out.println(newUser.toString()); ois.close(); }}

查看输出的结构

common.lang.User1@6ef64f64[  name=yaomy  age=23]common.lang.User1@184c9860[  name=  age=0]

根据输出的结果可以看到,对User1进行序列化然后再反序列化之后对象的属性都恢复成了默认值,即,之前那个对象的状态没有被持久保存下来,这就是Externalization和Serialization接口的区别,其中前者接口会被恢复成为默认值,后者接口不会恢复默认值。

如果需要恢复,这里就需要重写两个抽象方法,分别是writeExternal与readExternal两个抽象方法。

package common.lang;
import java.io.Externalizable;import java.io.IOException;import java.io.ObjectInput;import java.io.ObjectOutput;
import org.apache.commons.lang3.builder.ToStringBuilder;import org.apache.commons.lang3.builder.ToStringStyle;
public class User1 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; } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) .append("name", name) .append("age", age) .toString(); } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(name); out.writeInt(age); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = (String)in.readObject(); age = in.readInt(); }}

package common.lang;
import java.io.File;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 SerializableDemo1 {
public static void main(String[] args) throws Exception, IOException { //初始化对象 User1 user = new User1(); user.setName("yaomy"); user.setAge(23); System.out.println(user); //序列化对象到文件中 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("template")); oos.writeObject(user); oos.close(); //反序列化 File file = new File("template"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); User1 newUser = (User1)ois.readObject(); System.out.println(newUser.toString()); ois.close(); }}

输出的结果


common.lang.User1@6cd66725[  name=yaomy  age=23]common.lang.User1@19160e64[  name=yaomy  age=23]


静态变量的序列化

实例

public class Test implements Serializable {     private static final long serialVersionUID = 1L;     public static int staticVar = 5;     public static void main(String[] args) {        try {            //初始时staticVar为5            ObjectOutputStream out = new ObjectOutputStream(                    new FileOutputStream("result.obj"));            out.writeObject(new Test());            out.close();             //序列化后修改为10            Test.staticVar = 10;             ObjectInputStream oin = new ObjectInputStream(new FileInputStream(                    "result.obj"));            Test t = (Test) oin.readObject();            oin.close();                         //再读取,通过t.staticVar打印新的值            System.out.println(t.staticVar);                     } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }}

代码阐述一下过程,在main方法中,对象序列化以后,修改静态变量的数值,再把序列化后的对象读取出来,此时输出的值为10. 理解如下:打印的staticVar是从读取对象里获得的,打印10的原因是因为序列化时,不保存静态变量,只保存内存中的状态。此时修改静态变量的值,修改的是类中的值,输出的也是类中的值,和内存无关。



Transient关键字

Transient关键字,加上以后,可以阻止该变量被序列化到文件中,反序列化以后,变量的值设定为初始值。


有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号


好文章,我在看❤️

浏览 17
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报