Java序列化和反序列化相关应用技术及实例
- 格式:pdf
- 大小:278.64 KB
- 文档页数:14
java序列化与反序列化的实例详解1.Java序列化与反序列化Java序列化是指把Java对象转换为字节序列的过程;⽽Java反序列化是指把字节序列恢复为Java对象的过程。
2.为什么需要序列化与反序列化我们知道,当两个进程进⾏远程通信时,可以相互发送各种类型的数据,包括⽂本、图⽚、⾳频、视频等,⽽这些数据都会以⼆进制序列的形式在⽹络上传送。
那么当两个Java进程进⾏通信时,能否实现进程间的对象传送呢?答案是可以的。
如何做到呢?这就需要Java序列化与反序列化了。
换句话说,⼀⽅⾯,发送⽅需要把这个Java对象转换为字节序列,然后在⽹络上传送;另⼀⽅⾯,接收⽅需要从字节序列中恢复出Java对象。
序列化简介Java 提供了⼀种对象序列化的机制,该机制中,⼀个对象可以被表⽰为⼀个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
将序列化对象写⼊⽂件之后,可以从⽂件中读取出来,并且对它进⾏反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以⽤来在内存中新建对象。
整个过程都是 Java 虚拟机(JVM)独⽴的,也就是说,在⼀个平台上序列化的对象可以在另⼀个完全不同的平台上反序列化该对象。
类 ObjectInputStream 和 ObjectOutputStream 是⾼层次的数据流,它们包含序列化和反序列化对象的⽅法。
ObjectOutputStream 类包含很多写⽅法来写各种数据类型,但是⼀个特别的⽅法例外:publicfinalvoidwriteObject(Objectx)throwsIOException上⾯的⽅法序列化⼀个对象,并将它发送到输出流。
相似的 ObjectInputStream 类包含如下反序列化⼀个对象的⽅法:publicfinalObjectreadObject()throwsIOException, ClassNotFoundException该⽅法从流中取出⼀个对象,并将对象反序列化。
Hessian序列化和反序列化实现先聊聊 Java的序列化,Java官⽅的序列化和反序列化的实现被太多⼈吐槽,这得归于Java官⽅序列化实现的⽅式。
1、Java序列化的性能经常被吐槽。
2、Java官⽅的序列化后的数据相对于⼀些优秀的序列化的⼯具,还是要⼤不少,⽐如probuf,这⼤⼤影响存储和传输的效率。
3、Java序列化⼀定需要实现Serializable接⼝4、Java序列化的 serialVersionUID 也是个⼤坑另外,序列化和反序列化中还需要考虑:跨语⾔,新旧对象版本兼容,安全,性能。
今天主要来说说,Hessian2是如何来解决这些问题的?⼀、跨语⾔:hessian提供了⼀整套的byte[]的写⼊规范,这个规范为其他的语⾔实现hessian的序列化和反序列化提供了可能。
/doc/hessian-serialization.html⽬前hessian2已经⽀持了⾮常多语⾔,Java,Node,php,Erlang,c#.......⼆、新旧对象版本兼容:hessian2将类的描述信息写⼊byte[]中,以便于在反序列化时候能正常。
但是这样就带来了⼀个问题:序列化后的内容较⼤。
三、安全,hessian序列化时,会调⽤writeReplace⽅法得到⼀个新的对象,能将对象中的⼀些值进⾏加密后在进⾏序列化。
四、性能:hessian2的序列化在内容的序列化上做了⼀些优化,hessian2将需要序列化的多个相同的对象只会写⼊⼀次,其他⽤到该对象的只使⽤对象的引⽤,⽽不重新写⼊对象的描述信息和值信息。
但是hessian2在描述信息上写⼊的信息来兼容动态化的反序列化⽀持,所以内容相对于⼀些描述性的序列化⼯具(thrift,protobuf)来说,在性能上没有优势。
再回到序列化,相对于 Java来说,hessian的序列化从跨语⾔,新旧对象的版本兼容,安全以及性能⽅⾯都做的好,主要体现在:⼀、Java的序列化⽆法跨语⾔。
Java面试题详解Java中的序列化和反序列化Java中的序列化和反序列化序列化和反序列化是Java中重要的概念,用于实现对象的持久化和数据传输。
本文将详细解析Java中的序列化和反序列化的概念、使用方法以及相关注意事项。
一、序列化和反序列化的概念1. 序列化序列化是指将Java对象转换为字节流的过程,以便在网络传输或存储到文件中。
序列化使得对象能够被传输和保存,也可以在不同的平台和语言间进行通信和数据交换。
2. 反序列化反序列化是指将字节流转换为Java对象的过程。
反序列化是序列化的逆过程,通过反序列化可以将保存在文件或通过网络传输的字节流重新转化为Java对象。
二、Java中的序列化和反序列化实现方式Java中提供了两种主要的序列化和反序列化的实现方式:Serializable和Externalizable接口,并且默认的序列化机制是基于Serializable接口的。
1. Serializable接口Serializable接口是Java中的一个标记接口,实现该接口的类可以通过默认的序列化机制进行序列化和反序列化。
需要注意的是,实现Serializable接口的类的所有成员变量都将被序列化,包括私有成员变量。
2. Externalizable接口Externalizable接口继承自Serializable接口,是一个自定义序列化和反序列化机制的接口。
实现Externalizable接口的类必须实现writeExternal和readExternal两个方法,用于控制对象的序列化和反序列化过程。
相对于Serializable接口,Externalizable接口提供了更大的灵活性和性能上的优势。
三、序列化和反序列化的应用与注意事项1. 序列化的应用序列化主要应用于以下场景:- 对象的持久化:将对象保存到文件,以便在程序下次运行时恢复对象的状态。
- 远程方法调用:客户端和服务器之间传递Java对象。
序列化与反序列化的原理以及利⽤和防御1、序列化和反序列化的概念序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
序列化就是把对象转换成字节流,便于保存在内存、⽂件、数据库中;反序列化即逆过程,由字节流还原成对象。
Java中的ObjectOutputStream类的writeObject()⽅法可以实现序列化,类ObjectInputStream类的readObject()⽅法⽤于反序列化。
下⾯是将字符串对象先进⾏序列化,存储到本地⽂件,然后再通过反序列化进⾏恢复如果Java应⽤对⽤户输⼊,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输⼊,让反序列化产⽣⾮预期的对象,⾮预期的对象在产⽣过程中就有可能带来任意代码执⾏问题的根源在于类ObjectInputStream在反序列化时,没有对⽣成的对象的类型做限制;假若反序列化可以设置Java类型的⽩名单2、序列化的⽬的与⽤到序列化的情况当你想把的内存中的对象状态保存到⼀个⽂件中或者数据库中时候;当你想⽤套接字在⽹络上传送对象的时候;当你想通过RMI传输对象的时候;2.1对象序列化的步骤如下(1)创建对象输⼊流,它可以包装⼀个其他类型的⽬标输⼊流,例如:⽂件输出流。
(2)通过对象输⼊流的writeObject()⽅法写对象。
2.2.对象的反序列化如下:(1)创建对象输⼊流,同样的,可以包含其他类型的⽬标输出流,例如:⽂件输⼊流。
(2)通过对象输⼊流的readObject()⽅法读取对象。
3、漏洞挖掘基本⼿段:从可控数据的反序列化或间接的反序列化接⼝⼊⼿,在此基础上尝试构造序列化对象。
⾸先拿到⼀个Java应⽤,需要找到⼀个接受外部输⼊的序列化对象的接收点,即反序列化漏洞的触发点。
我们可以通过审计源码中对反序列化函数的调⽤(例如readObject())来寻找,也可以直接通过对应⽤交互流量进⾏抓包,查看流量中是否包含java序列化数据来判断,java序列化数据的特征为以标记(ac ed 00 05)开头。
Java中的序列化与反序列化技巧详解序列化与反序列化是Java中非常重要的概念和技术。
它们可以将对象转换为字节流,以便在网络上传输或者保存到文件中。
在本文中,我们将详细探讨Java中的序列化与反序列化技巧,包括如何实现序列化和反序列化,如何处理版本兼容性问题以及一些常见的注意事项。
一、序列化和反序列化的基本概念1. 序列化:将对象转换为字节流的过程称为序列化。
序列化后的字节流可以被保存到文件中或者通过网络传输。
2. 反序列化:将字节流转换为对象的过程称为反序列化。
反序列化可以从文件中读取字节流或者从网络中接收字节流。
3. Serializable接口:Java中的序列化和反序列化是通过Serializable接口实现的。
如果一个类实现了Serializable接口,那么它的对象可以被序列化和反序列化。
二、如何实现序列化和反序列化1. 实现Serializable接口:要使一个类可以被序列化,只需要让该类实现Serializable接口即可。
Serializable接口是一个标记接口,没有任何方法需要实现。
2. ObjectOutputStream和ObjectInputStream:Java提供了ObjectOutputStream和ObjectInputStream两个类来实现序列化和反序列化。
可以使用这两个类的writeObject()和readObject()方法来进行序列化和反序列化。
3. 序列化和反序列化的示例代码:```java// 序列化try {FileOutputStream fileOut = new FileOutputStream("object.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut);out.writeObject(object);out.close();fileOut.close();System.out.println("Serialized data is saved in object.ser");} catch (IOException i) {i.printStackTrace();}// 反序列化try {FileInputStream fileIn = new FileInputStream("object.ser");ObjectInputStream in = new ObjectInputStream(fileIn);Object object = (Object) in.readObject();in.close();fileIn.close();System.out.println("Deserialized data is loaded from object.ser"); } catch (IOException i) {i.printStackTrace();} catch (ClassNotFoundException c) {c.printStackTrace();}```三、版本兼容性问题的处理在进行序列化和反序列化时,可能会遇到版本兼容性的问题。
java序列化和serialVersionUID的使⽤⽅法实例java序列化和serialVersionUID的使⽤⽅法实例1、序列化:序列化可以将⼀个java对象以⼆进制流的⽅式在⽹络中传输并且可以被持久化到数据库、⽂件系统中,反序列化则是可以把之前持久化在数据库或⽂件系统中的⼆进制数据以流的⽅式读取出来重新构造成⼀个和之前相同内容的java对象。
2、序列化的作⽤:第⼀种:⽤于将java对象状态储存起来,通常放到⼀个⽂件中,使下次需要⽤到的时候再读取到它之前的状态信息。
第⼆种:可以让java对象在⽹络中传输。
3、序列化的实现:1)、需要序列化的类需要实现Serializable接⼝,该接⼝没有任何⽅法,只是标⽰该类对象可被序列化。
2)、序列化过程:使⽤⼀个输出流(如:FileOutputStream)来构造⼀个ObjectOutputStream(对象流)对象,接着,使⽤ObjectOutputStream对象的writeObject(Object obj)⽅法就可以将参数为obj的对象写出(即保存其状态)3)、反序列化过程:使⽤⼀个输⼊流(如:FileInputStream)来构造⼀个ObjectInputStream(对象流)对象,接着,使⽤ObjectInputStream对象的readObject(Object obj)⽅法就可以将参数为obj的对象读出(即获取其状态)4、静态long类型常量serialVersionUID的作⽤:如果没有设置这个值,你在序列化⼀个对象之后,改动了该类的字段或者⽅法名之类的,那如果你再反序列化想取出之前的那个对象时就可能会抛出异常,因为你改动了类中间的信息,serialVersionUID是根据类名、接⼝名、成员⽅法及属性等来⽣成⼀个64位的哈希字段,当修改后的类去反序列化的时候发现该类的serialVersionUID值和之前保存在问价中的serialVersionUID 值不⼀致,所以就会抛出异常。
java对象序列化与对象反序列化Java对象序列化与对象反序列化是Java中比较重要的一个技术,可以帮助开发者对Java对象进行持久化存储、传输以及分布式调用,保证Java程序的可靠性和安全性。
本文将从概念、原理、用途和实现方面介绍Java对象序列化与对象反序列化。
一、概念Java对象序列化是指将Java对象转换为二进制流的过程,可以用于将对象保存在硬盘或者网络传输。
序列化后的对象包含Java对象的数据和类信息,可以在反序列化后还原为原来的对象,对Java对象进行快速和方便的持久化存储和传输。
Java对象反序列化是指将序列化的二进制数据流还原为Java对象的过程。
在反序列化过程中,Java虚拟机通过读取序列化数据流,重建对象的状态和类信息。
反序列化后的对象可以直接使用,不需要重新编写或者初始化数据和类信息。
二、原理Java对象序列化与对象反序列化都是通过Java IO流实现的。
在序列化过程中,将Java对象的数据和类信息通过序列化流转换为字节流,可以用于保存到硬盘或传输。
在反序列化过程中,通过反序列化流读取序列化的字节流,反解析还原为Java对象。
Java对象序列化过程中,将Java对象的数据和类信息转换为二进制流,并将其传输到远程对象或存储到本地;反序列化过程中,将序列化的二进制流转换为Java对象,并还原对象的状态和类信息。
序列化和反序列化过程中需要考虑Java对象的类加载机制、安全性和性能等因素。
三、用途Java对象序列化和对象反序列化可以用于多种场景,如:1. 分布式计算中,用于远程方法调用(RMI)或远程(EJB)对象调用;2. 对象数据持久化,将Java对象保存到硬盘或数据库中,实现数据的持久化存储和读取;3. 网络数据传输,将Java对象通过网络传输,实现数据的跨机通信;4. 序列化数据缓存,将Java对象序列化后保存到缓存中,提高访问速度和性能。
Java对象序列化和对象反序列化广泛应用于面向对象的软件开发,保证Java程序的可靠性和安全性,并且使得Java程序具有良好的可扩展性和互操作性。
java对象的序列化以及反序列化详解⼀、概念序列化:把创建出来的对象(new出来的对象),以及对象中的成员变量的数据转化为字节数据,写到流中,然后存储到硬盘的⽂件中。
反序列化:可以把序列化后的对象(硬盘上的⽂件中的对象数据),读取到内存中,然后就可以直接使⽤对象。
这样做的好处是不⽤再⼀次创建对象了,直接反序列化就可以了。
使⽤场景:在创建对象并给所创建的对象赋予了值后,当前创建出来的对象是存放在堆内存中的,当JVM停⽌后,堆中的对象也被释放了,如果下⼀次想要继续使⽤之前的对象,需要再次创建对象并赋值。
然⽽使⽤序列化对象,就可以把创建出来的对象及对象中数据存放到硬盘的⽂件中,下次使⽤的时候不⽤在重新赋值,⽽是直接读取使⽤即可。
对象直接转换为字节的形式进⾏⽹络传输⼆、相关API介绍序列化序列化对象所属的类是ObjectOutputStream,如下图所⽰:说明:ObjectOutputStream类可以把对象及其数据写⼊到流中或⽹络中。
构造函数如下图所⽰:写出功能:反序列化反序列化对象所属的类是ObjectInputStream类:说明:序列化输出流对象和反序列化输出流对象都不具备读写能⼒,分别依赖FileOutputStream和FileInputStream类来进⾏读写⽂件。
构造函数如下图所⽰:读取功能:三、实战序列化需求:把Student类创建的对象持久化保存。
分析和步骤:1)⾃定义⼀个Student类,并定义name和age属性;2)定义⼀个测试类,在这个测试类中创建Student类的对象s;3)创建序列化对象objectOutputStream,同时创建输出流并关联硬盘上的⽂件;4)使⽤序列化对象objectOutputStream调⽤writeObject()函数持久化保存学⽣对象s;5)释放序列化对象流的资源;Student类如下:需要实现序列化接⼝Serializable,它是⼀个标记性接⼝。
java序列化与反序列化的使⽤⽅法汇总⼀、概念java对象序列化的意思就是将对象的状态转化成字节流,以后可以通过这些值再⽣成相同状态的对象。
对象序列化是对象持久化的⼀种实现⽅法,它是将对象的属性和⽅法转化为⼀种序列化的形式⽤于存储和传输。
反序列化就是根据这些保存的信息重建对象的过程。
序列化:将java对象转化为字节序列的过程。
反序列化:将字节序列转化为java对象的过程。
⼆、为什么要序列化和反序列化我们知道,当两个进程进⾏远程通信时,可以相互发送各种类型的数据,包括⽂本、图⽚、⾳频、视频等,⽽这些数据都会以⼆进制序列的形式在⽹络上传送。
那么当两个Java进程进⾏通信时,能否实现进程间的对象传送呢?答案是可以的。
如何做到呢?这就需要Java序列化与反序列化了。
换句话说,⼀⽅⾯,发送⽅需要把这个Java对象转换为字节序列,然后在⽹络上传送;另⼀⽅⾯,接收⽅需要从字节序列中恢复出Java对象。
当我们明晰了为什么需要Java序列化和反序列化后,我们很⾃然地会想Java序列化的好处。
其好处⼀是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在⽂件⾥),⼆是,利⽤序列化实现远程通信,即在⽹络上传送对象的字节序列。
三、涉及到的javaAPI java.io.ObjectOutputStream表⽰对象输出流,它的writeObject(Object obj)⽅法可以对参数指定的obj对象进⾏序列化,把得到的字节序列写到⼀个⽬标输出流中。
java.io.ObjectInputStream表⽰对象输⼊流,它的readObject()⽅法源输⼊流中读取字节序列,再把它们反序列化成为⼀个对象,并将其返回。
只有实现了Serializable或Externalizable接⼝的类的对象才能被序列化,否则抛出异常。
四、序列化和反序列化的步骤序列化:步骤⼀:创建⼀个对象输出流,它可以包装⼀个其它类型的⽬标输出流,如⽂件输出流:ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(“⽬标地址路径”));步骤⼆:通过对象输出流的writeObject()⽅法写对象:out.writeObject("Hello");out.writeObject(new Date());反序列化:步骤⼀:创建⼀个对象输⼊流,它可以包装⼀个其它类型输⼊流,如⽂件输⼊流:ObjectInputStream in = new ObjectInputStream(new fileInputStream(“⽬标地址路径”));步骤⼆:通过对象输出流的readObject()⽅法读取对象:String obj1 = (String)in.readObject();Date obj2 = (Date)in.readObject();说明:为了正确读取数据,完成反序列化,必须保证向对象输出流写对象的顺序与从对象输⼊流中读对象的顺序⼀致。
一、什么是序列化序列化 (Serialization)是指将对象的状态信息转换为可以存储或传输的形式的过程。
在序列化期间,对象将其当前状态写入到临时或持久性存储区。
以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
简单来说:序列化:将数据结构或对象转换成二进制串的过程序列化反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程反序列化下面是将字符串对象先进行序列化,存储到本地文件,然后再通过反序列化进行恢复的样例代码:public static void main(String args[]) throws Exception {String obj = “hello world!”;// 将序列化对象写入文件object.db中FileOutputStream fos = new FileOutputStream(“object.db”);ObjectOutputStream os = new ObjectOutputStream(fos);os.writeObject(obj);os.close();// 从文件object.db中读取数据FileInputStream fis = new FileInputStream(“object.db”);ObjectInputStream ois = new ObjectInputStream(fis);// 通过反序列化恢复对象objString obj2 = (String)ois.readObject();ois.close();}二、反序列化漏洞原理反序列化漏洞的本质就是反序列化机制打破了数据和对象的边界,导致攻击者注入的恶意序列化数据在反序列化过程中被还原成对象,控制了对象就可能在目标系统上面执行攻击代码。
Java 序列化应用于RMI JMX JMS 技术中。
三、漏洞危害案例一:Apache ActiveMQ 5.12.0 远程代码执行漏洞(JMS)Apache ActiveMQ 5.13.0之前5.x版本中存在安全漏洞,该漏洞源于程序未能限制可在代理中序列化的类。
java 序列化(Serializable)的作用和反序列化1、序列化是干什么的? 简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以 把保存的对象状态再读出来。
虽然你可以用你自己的各种各样的方法来保 存 object states,但是 Java 给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。
2、什么情况下需要序列化 a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候; b)当你想用套接字在网络上传送对象的时候; c)当你想通过 RMI 传输对象的时候; 3、当对一个对象实现序列化时,究竟发生了什么? 在没有序列化前,每个保存在堆(Heap)中的对象都有相应的状态(state),即实例变 量(instance ariable)比如: java 代码 Foo myFoo = new Foo(); myFoo .setWidth(37); myFoo.setHeight(70); 当 通过下面的代码序列化之后,MyFoo 对象中的 width 和 Height 实例变量的值(37, 70)都被保存到 foo.ser 文件中,这样以后又可以把它 从文件中读出来,重新在堆中创建 原来的对象。
当然保存时候不仅仅是保存对象的实例变量的值,JVM 还要保存一些小量信 息,比如类的类型等以便恢复原来的对 象。
java 代码FileOutputStream fs = new FileOutputStream("foo.ser");ObjectOutputStream os = new ObjectOutputStream(fs);os.writeObject(myFoo);4、实现序列化(保存到一个文件)的步骤 a、Make a FileOutputStream java 代码 FileOutputStream fs = new FileOutputStream(“foo.ser”); b、Make a ObjectOutputStream java 代码ObjectOutputStream os = new ObjectOutputStream(fs);c、write the objectjava 代码os.writeObject(myObject1);os.writeObject(myObject2);os.writeObject(myObject3);d、 close the ObjectOutputStreamjava 代码os.close(); 5、举例说明Java 代码package com.hotye.dchaoxiong.serializabletest;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class Box implements Serializable {1.private static final long serialVersionUID = 1L;2.private int width;3.private int height;4.private String name;5.public static void main(String[] args) {6.try {7.Box myBox = new Box();8.myBox.setWidth(50);9.myBox.setHeight(30);10.myBox.setName(“雕戈”);11.FileOutputStream fs = new FileOutputStream(“serializableObject.txt”);12.ObjectOutputStream os = new ObjectOutputStream(fs);13.os.writeObject(myBox);14.os.close();15.fs.close();16.} catch (Exception ex) {17.ex.printStackTrace();18.}19.try {20.FileInputStream fis = new FileInputStream(“serializableObject.txt”);21.ObjectInputStream ois = new ObjectInputStream(fis);22.Box box = (Box) ois.readObject();23.System.out.println(box.getWidth());24.System.out.println(box.getHeight());25.System.out.println(box.getName());26.ois.close();27.fis.close();28.} catch (Exception e) {29.e.printStackTrace();30.}31.}32.public void setHeight(int height) {33.this.height = height;34.}35.public int getHeight() {36.return height;37.}38.public void setWidth(int width) {39.this.width = width;40.}41.public int getWidth() {42.return width;43.}44.public void setName(String name) {45. = name;46.}47.public String getName() {48.return name;49.}50.}6、相关注意事项a)序列化时,只对对象的状态进行保存,而不管对象的方法;b)当一个父类实现序列化,子类自动实现序列化,不需要显式实现 Serializable 接口;c)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;d)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:1.安全方面的原因,比如一个对象拥有 private,public 等 field,对于一个要传输的对象,比如写到文件,或者进行 rmi 传输 等等,在序列化进行传输的过程中,这个对象的 private等域是不受保护的。
JAVA基础4---序列化和反序列化深⼊整理(JDK序列化)⼀、什么是序列化和反序列化?序列化:将对象状态信息转化成可以存储或传输的形式的过程(Java中就是将对象转化成字节序列的过程)反序列化:从存储⽂件中恢复对象的过程(Java中就是通过字节序列转化成对象的过程)⼆、为什么要序列化和反序列化?Java中对象都是存储在内存中,准确地说是JVM的堆或栈内存中,可以各个线程之间进⾏对象传输,但是⽆法在进程之间进⾏传输。
另外如果需要在⽹络传输中传输对象也没有办法,同样内存中的对象也没有办法直接保存成⽂件。
所以需要对对象进⾏序列化,序列化对象之后⼀个个的Java对象就变成了字节序列,⽽字节序列是可以传输和存储的。
⽽反序列化就可以通过序列化⽣产的字节序列再恢复成序列化之前的对象状态及信息。
总结:1、进程之间传输对象(如RPC、RMI通信)2、⽹络通信时进⾏传输对象3、持久化对象时需要将对象序列化三、怎么序列化和反序列化?实现序列化的⽅式有很多种,常⽤的⽅式有如下⼏种:3.1、JDK序列化JDK序列化时JDK⾃带的序列化⽅式,使⽤其他也⽐较⽅便,只需要序列化的类实现了Serializable接⼝即可,Serializable接⼝没有定义任何⽅法和属性,所以只是起到了标识的作⽤,表⽰这个类是可以被序列化的。
如果没有实现Serializable接⼝⽽进⾏序列化操作就会抛出NotSerializableException异常。
能够序列化的字段:属性变量、⽗类的属性变量(⽗类也需要实现Serializablie接⼝)不能序列化的字段:静态变量、⽗类的属性变量、关键字transient修饰的变量、没有实现Serializable接⼝的对象属性3.1.1、Serializable接⼝案例定义类User、Person、Home、School分别如下1public class Home implements Serializable {2private String address;34public String getAddress() {5return address;6 }78public void setAddress(String address) {9this.address = address;10 }11 }1public class School {2private String schoolName;34public String getSchoolName() {5return schoolName;6 }78public void setSchoolName(String schoolName) {9this.schoolName = schoolName;10 }11 }1public class Person implements Serializable {23public static String parentType = "Person"; //⽗类静态变量45private String sex;//性别67public String getSex() {8return sex;9 }1011public void setSex(String sex) {12this.sex = sex;13 }14 }public class User extends Person implements Serializable {public static boolean alive; //静态变量private Long userId;//Long 类型private int age; //int 类型private String userName; //string 类型private String password; //string 类型private transient String IDCard; //不序列化的字段private Date birth; //Date类型private Home home; // 可以序列化的对象类型private School school; //不可以序列化的对象类型List<User> friends; //List类型/** set get ⽅法省略*/}案例中序列化的类为User,继承类Person,分别含有类Home和School的对象属性,序列化测试代码如下:1public class MainTest {2public static void main(String[] args) throws Exception{3 User user = new User();4 user.setAge(10);5 user.setBirth(new Date());6 user.setPassword("123456");7 user.setUserName("Jack");8 user.setUserId(100L);9 user.setSex("男");10 user.setIDCard("131313131313113");11 user.parentType = "son";//修改⽗类静态变量12 user.alive = true; //修改User类的静态变量1314 Home home = new Home();15 home.setAddress("中国浙江");16 School school = new School();17 school.setSchoolName("清华⼤学");18 user.setHome(home);//设置对象属性19// user.setSchool(school);//设置对象属性 (因为School类没有实现Seriliazable接⼝,所以如果设置就会报错)2021 List<User> friends = new ArrayList<User>();22 User userF = new User();23 userF.setUserId(101L);24 userF.setUserName("Friend");25 friends.add(userF);26 user.setFriends(friends);2728//序列化29 serializer(user);30//反序列化31 User newUser = derializer();32//验证33 System.out.println("验证两个对象是否相等");34 System.out.println("原对象地址:"+user.toString());35 System.out.println("新对象地址:"+newUser.toString());36 System.out.println("******************");37 System.out.println("打印两个对象");38 System.out.println("原对象数据:"+JSON.toJSON(user).toString());39 System.out.println("新对象数据:"+JSON.toJSON(newUser).toString());40 }4142/**序列化对象*/43private static void serializer(User user)throws Exception{44 ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("/Users/xxw/testlog/user.txt")));45 outputStream.writeObject(user);46 outputStream.close();47 }4849/**反序列化对象*/50private static User derializer()throws Exception{51 ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("/Users/xxw/testlog/user.txt")));52 User user = (User) inputStream.readObject();53 inputStream.close();54return user;55 }56 }测试结果为:1验证两个对象是否相等2原对象地址:er@3764951d3新对象地址:er@4783da3f4 ******************5打印两个对象6原对象数据:{"iDCard":"131313131313113","password":"123456","sex":"男","birth":1573203467764,"userName":"Jack","userId":100,"age":10,"friends":[{"userName":"Friend","userId":101,"age":0}],"home":{"address":"中国浙江" 7新对象数据:{"password":"123456","sex":"男","birth":1573203467764,"userName":"Jack","userId":100,"age":10,"friends":[{"userName":"Friend","userId":101,"age":0}],"home":{"address":"中国浙江"}}这⾥User类的School属性没有实现Serializable接⼝,所以如果给school属性赋值然后进⾏序列化就会报错,结果如下:1 Exception in thread "main" java.io.NotSerializableException: com.lucky.demo.base.seralizer.demo.School2 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)3 at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)4 at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)5 at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)6 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)7 at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)8 at com.lucky.demo.base.seralizer.demo.MainTest.serializer(MainTest.java:59)9 at com.lucky.demo.base.seralizer.demo.MainTest.main(MainTest.java:43)⽽如果User类的⽗类Person没有实现Serializable接⼝,那么序列化的时候不会报错,但是⽗类中的属性在反序列化之后字段就会没有,结果如下:1打印两个对象2原对象数据:{"iDCard":"131313131313113","password":"123456","sex":"男","birth":1573203839905,"userName":"Jack","userId":100,"age":10,"friends":[{"userName":"Friend","userId":101,"age":0}],"home":{"address":"中国浙江" 3新对象数据:{"password":"123456","birth":1573203839905,"userName":"Jack","userId":100,"age":10,"friends":[{"userName":"Friend","userId":101,"age":0}],"home":{"address":"中国浙江"}}这⾥就没有了⽗类的属性sex字段3.1.2、Serializable接⼝实现原理Serializable接⼝是⼀个空接⼝,没有定义任何的⽅法和属性,所以Serialiazable接⼝的作⽤就是起到⼀个标识的作⽤,源码如下1public interface Serializable {2 }Serializable接⼝既然是标识的作⽤,那么就需要在实际序列化操作的时候进⾏识别,⽽实际的序列化操作是通过ObjectOutputStream和ObjectInputStream实现的,那么接下来就看下这两个类的是如何实现序列化和反序列化的3.1.2.1、ObjectOutputStream源码解析构造函数如下1public ObjectOutputStream(OutputStream out) throws IOException {2 verifySubclass();3 bout = new BlockDataOutputStream(out);4 handles = new HandleTable(10, (float) 3.00);5 subs = new ReplaceTable(10, (float) 3.00);6 enableOverride = false;7 writeStreamHeader();8 bout.setBlockDataMode(true);9if (extendedDebugInfo) {10 debugInfoStack = new DebugTraceInfoStack();11 } else {12 debugInfoStack = null;13 }14 }OutoutStream表⽰保存的⼆进制流,也就是将序列化的对象保存到这个⼆进制流中,再看下具体的序列化⽅法源码如下:1public final void writeObject(Object obj) throws IOException {2if (enableOverride) {//enableOverride 表⽰是否可以被覆盖,默认为false3 writeObjectOverride(obj);4return;5 }6try {7//执⾏具体的序列化操作8writeObject0(obj, false);9 } catch (IOException ex) {10if (depth == 0) {11 writeFatalException(ex);12 }13throw ex;14 }15 }最终执⾏了writeObject0(obj, false)⽅法,代码如下:1private void writeObject0(Object obj, boolean unshared)2throws IOException3 {4boolean oldMode = bout.setBlockDataMode(false);5 depth++;6try {7// handle previously written and non-replaceable objects8// 处理已经处理过的和不可替换的对象,这些是不可序列化的9int h;10if ((obj = subs.lookup(obj)) == null) {11 writeNull();12return;13 } else if (!unshared && (h = handles.lookup(obj)) != -1) {14 writeHandle(h);15return;16 } else if (obj instanceof Class) {17 writeClass((Class) obj, unshared);18return;19 } else if (obj instanceof ObjectStreamClass) {20 writeClassDesc((ObjectStreamClass) obj, unshared);21return;22 }2324// check for replacement object25 Object orig = obj;26//获取对象的Class对象27 Class<?> cl = obj.getClass();28 ObjectStreamClass desc;29for (;;) {30// REMIND: skip this check for strings/arrays?31 Class<?> repCl;32//获取Class的描述信息,并且判断是否是Serializable接⼝33 desc = ObjectStreamClass.lookup(cl, true);34if (!desc.hasWriteReplaceMethod() ||35 (obj = desc.invokeWriteReplace(obj)) == null ||36 (repCl = obj.getClass()) == cl)37 {38break;39 }40 cl = repCl;41 }4243//如果允许被替换的情况44if (enableReplace) {45 Object rep = replaceObject(obj);46if (rep != obj && rep != null) {47 cl = rep.getClass();48 desc = ObjectStreamClass.lookup(cl, true);49 }50 obj = rep;51 }5253// if object replaced, run through original checks a second time54// 如果对象被替换了,只有是ObjectOutputStream的⼦类才会出现55if (obj != orig) {56 subs.assign(orig, obj);57if (obj == null) {58 writeNull();59return;60 } else if (!unshared && (h = handles.lookup(obj)) != -1) {61 writeHandle(h);62return;64 writeClass((Class) obj, unshared);65return;66 } else if (obj instanceof ObjectStreamClass) {67 writeClassDesc((ObjectStreamClass) obj, unshared);68return;69 }70 }7172// remaining cases73/**序列化不同类型的对象,分别序列化String、数组、枚举类型74 * 对于Integer、Long等都属于实现了Serializable接⼝的数据类型*/75 if (obj instanceof String) {//序列化字符串类型对象76 writeString((String) obj, unshared);77 } else if (cl.isArray()) {//序列化数组类型对象78 writeArray(obj, desc, unshared);79 } else if (obj instanceof Enum) {//序列化枚举类型对象80 writeEnum((Enum<?>) obj, desc, unshared);81 } else if (obj instanceof Serializable) {//序列化实现了Serializable接⼝的数据类型82 writeOrdinaryObject(obj, desc, unshared);83 } else {//抛出不可序列化异常84 if (extendedDebugInfo) {85 throw new NotSerializableException(86 cl.getName() + "\n" + debugInfoStack.toString());87 } else {88 throw new NotSerializableException(cl.getName());89 }90 }91 } finally {92 depth--;93 bout.setBlockDataMode(oldMode);94 }95 }96 }前⾯都是在做各种检查,实际有效的代码就是从75⾏开始,分别针对不同类型的对象分别执⾏不同的序列化⽅法writeString⽅法的逻辑就是将字符串按字节的⽅式进⾏序列化,底层就是通过数组复制的⽅式获取到char[],然后写⼊到缓存的序列化的byte[]数组中1 System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);writeArray⽅法的逻辑就是先判断数组的数据类型是什么,如果是基本数据类型之间写⼊byte数字,如果是对象类型就调⽤writeObject0⽅法writeEnum⽅法的逻辑是直接写⼊枚举的值⽽对于对象类型是⽐较复杂的,也就是writeOrdinaryObject⽅法,逻辑如下:1private void writeOrdinaryObject(Object obj,2 ObjectStreamClass desc,3boolean unshared)4throws IOException5 {6if (extendedDebugInfo) {7 debugInfoStack.push(8 (depth == 1 ? "root " : "") + "object (class \"" +9 obj.getClass().getName() + "\", " + obj.toString() + ")");10 }11try {12//检查ObjectStreamClass对象13 desc.checkSerialize();1415//写⼊标记表⽰是Object类型16 bout.writeByte(TC_OBJECT);17//写⼊Class对象的描述信息18 writeClassDesc(desc, false);19 handles.assign(unshared ? null : obj);20if (desc.isExternalizable() && !desc.isProxy()) {21//写⼊实现了Externalizable接⼝的对象22 writeExternalData((Externalizable) obj);23 } else {24//写⼊实现了Serializable25 writeSerialData(obj, desc);26 }27 } finally {28if (extendedDebugInfo) {29 debugInfoStack.pop();30 }31 }32 }最终按实现了Externalizable接⼝或Serializable接⼝分别执⾏writeExternalData和writeSerialData⽅法,writeSerialData⽅法如下:1private void writeSerialData(Object obj, ObjectStreamClass desc)2throws IOException3 {4//获取类的描述信息对象5 ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();6for (int i = 0; i < slots.length; i++) {7 ObjectStreamClass slotDesc = slots[i].desc;8//判断该类是否⾃定义类writeObject⽅法,如果重写了该⽅法则按重写的逻辑处理9if (slotDesc.hasWriteObjectMethod()) {10 ObjectOutputStream.PutFieldImpl oldPut = curPut;11 curPut = null;12 SerialCallbackContext oldContext = curContext;1314if (extendedDebugInfo) {15 debugInfoStack.push(16 "custom writeObject data (class \"" +17 slotDesc.getName() + "\")");18 }19try {20 curContext = new SerialCallbackContext(obj, slotDesc);21 bout.setBlockDataMode(true);22//通过反射的⽅式执⾏⾃定义的writeObejct⽅法23 slotDesc.invokeWriteObject(obj, this);24 bout.setBlockDataMode(false);25 bout.writeByte(TC_ENDBLOCKDATA);26 } finally {27 curContext.setUsed();28 curContext = oldContext;30 debugInfoStack.pop();31 }32 }3334 curPut = oldPut;35 } else {36//如果没有⾃定义writeObject⽅法则按默认的⽅法写⼊属性数据37 defaultWriteFields(obj, slotDesc);38 }39 }40 }先是根据类的描述信息判断是否⾃定义了序列化⽅法writeObejct⽅法,如果⾃定义了就通过反射执⾏invokeWriteObejct⽅法,如果没有⾃定义则执⾏defaultWriteFields⽅法,defaultWriteFields⽅法逻辑如下:1private void defaultWriteFields(Object obj, ObjectStreamClass desc)2throws IOException3 {4 Class<?> cl = desc.forClass();5//校验对象的类信息是否和类描述信息⼀致6if (cl != null && obj != null && !cl.isInstance(obj)) {7throw new ClassCastException();8 }910//11 desc.checkDefaultSerialize();1213int primDataSize = desc.getPrimDataSize();14if (primVals == null || primVals.length < primDataSize) {15 primVals = new byte[primDataSize];16 }17 desc.getPrimFieldValues(obj, primVals);18 bout.write(primVals, 0, primDataSize, false);1920 ObjectStreamField[] fields = desc.getFields(false);//获取所有属性21 Object[] objVals = new Object[desc.getNumObjFields()];//获取对象类型属性22int numPrimFields = fields.length - objVals.length;23 desc.getObjFieldValues(obj, objVals);24for (int i = 0; i < objVals.length; i++) {//遍历对象类型属性数组25if (extendedDebugInfo) {26 debugInfoStack.push(27 "field (class \"" + desc.getName() + "\", name: \"" +28 fields[numPrimFields + i].getName() + "\", type: \"" +29 fields[numPrimFields + i].getType() + "\")");30 }31try {32//递归写⼊对象类型的属性33 writeObject0(objVals[i],34 fields[numPrimFields + i].isUnshared());35 } finally {36if (extendedDebugInfo) {37 debugInfoStack.pop();38 }39 }40 }41 }总结:序列化的整体逻辑就是遍历对象的所有属性,递归执⾏序列化⽅法,直到序列化的对象是String、Array或者是Eunm类,则按String、Array、Enum的序列化⽅式写⼊字节流中。
java 对象序列化反序列化方法Java中的对象序列化和反序列化是指将Java对象转化为字节序列的过程,以及将字节序列转化为Java对象的过程。
序列化可以将对象的状态保存到磁盘文件或通过网络传输,而反序列化则可以将保存的状态重新恢复为对象。
在Java中,序列化和反序列化是通过实现Serializable接口来实现的。
Serializable接口是一个标记接口,没有任何方法。
当一个类实现了Serializable接口,就表示该类的对象可以被序列化和反序列化。
要实现对象的序列化,只需要在类的定义中添加implements Serializable,如下所示:```javapublic class MyClass implements Serializable {// 类的定义}```接下来,就可以使用Java提供的ObjectOutputStream类将对象序列化为字节序列。
ObjectOutputStream类提供了writeObject()方法用于将对象写入输出流,如下所示:```javaMyClass obj = new MyClass();ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("obj.ser"));out.writeObject(obj);out.close();```在上述代码中,首先创建一个MyClass的对象obj,然后创建一个ObjectOutputStream对象out,并将其与文件输出流相连。
最后调用out的writeObject()方法将obj对象写入输出流,并关闭输出流。
要实现对象的反序列化,需要使用Java提供的ObjectInputStream类。
ObjectInputStream类提供了readObject()方法用于从输入流中读取字节序列并将其反序列化为对象,如下所示:```javaObjectInputStream in = new ObjectInputStream(new FileInputStream("obj.ser"));MyClass obj = (MyClass) in.readObject();in.close();```在上述代码中,首先创建一个ObjectInputStream对象in,并将其与文件输入流相连。
JAVA基础4---序列化和反序列化深⼊整理(Hessian序列化)⼀、Hessian序列化⽤法1、maven依赖<dependency><groupId>com.caucho</groupId><artifactId>hessian</artifactId><version>4.0.38</version></dependency>2、序列化和反序列化1/** Hessian序列化 */2public static byte[] hessianSerialize(Object object){3 Hessian2Output oo = null;4byte[] result = null;5try {6 ByteArrayOutputStream bos = new ByteArrayOutputStream();7oo = new Hessian2Output(bos);8 oo.writeObject(object);9 oo.flush();10 result = bos.toByteArray();11 } catch (IOException e) {12 e.printStackTrace();13 }14return result;15 }1617/** Hessian反序列化 */18public static Object hessianSerializeToObj(byte[] bytes){19 Object result = null;20try{21 ByteArrayInputStream is = new ByteArrayInputStream(bytes);22Hessian2Input input = new Hessian2Input(is);23result = input.readObject();24 }catch (Exception e){25 e.printStackTrace();26 }27return result;28 }Hessian的序列化和反序列化分别是依靠Hessian2Output和Hessian2Input来实现,⾸先是定义⼀个⼆进制字节流对象ByteArrayOutputStream和ByteArrayOutputStream对象,分别通过对应的Hessian对象进⾏⼆进制流的读写操作。
java序列化反序列化之xstream、protobuf、protostuff的⽐较与使⽤例⼦⽬录1. 背景2. 测试1. 环境2. ⼯具3. 说明4. 结果5. 结论3. xstream简单教程1. 准备2. 代码 4. protobuf简单教程1. 快速⼊门1. 下载.exe编译器2. 编写.proto⽂件3. 利⽤编译器编译.proto⽂件⽣成javabean4. 引⽤jar包5. 直接使⽤javabean⾃带的序列化、反序列化、提取属性等⽅法5. protostuff简单教程1. 快速⼊门1. 引⽤jar包2. 直接使⽤相关序列化、反序列化语法1、背景 项⽬中http通信离不开对象的序列化和反序列化,通过序列化技术,可以夸语⾔实现数据的传输,例如把⼀个对象序列化后的⼆进制数据、xml格式数据存在⽂本⽂件,下次通过读取⽂件,然后反序列化⼀下即可重新⽣成该对象,抑或通过⽹络把序列化后的数据传输到另⼀个终端,对⽅通过反序列化后也可以重新复制出⼀个⼤概相同的对象出来。
在⼀般项⽬中,xml是⼀个不错的选择,例如微信公众平台的⼤多数接⼝,就是使⽤xml技术来序列化传输的,学习成本低,可读性⾼,⽅便调试,可以直接在浏览器查看结果等等都是他的优点,对于对速度要求不⾼的系统来说,的确是⼀种不错的选择。
但如果系统对序列化效率要求很⾼,例如想⽐xml快上10倍?那么可能就得考虑换成其他技术了,例如——protobuf。
protobuf是⾕歌推出的与语⾔⽆关、平台⽆关的通信协议,⼀个对象经过protobuf序列化后将变成⼆进制格式的数据,所以他可读性差,但换来的是占⽤空间⼩,速度快。
使⽤protobuf要先使⽤特定的语法编写⼀个.proto⽂件,该⽂件与语⾔⽆关,然后使⽤特殊的编译器对该⽂件进⾏编译,⽣成与语⾔相关的⽂件,如java,那么将⽣成java的类,该类不仅有我们⾃⼰定义的属性,还提供了序列化,反序列化等其他⽅法。
序列化和反序列化的方式序列化和反序列化是计算机数据存储和传输过程中两个重要的操作。
序列化是将对象转化为字节流的过程,而反序列化是将这个字节流转换回对象的过程。
序列化和反序列化广泛应用于网络通信、文件存储、数据库存储、跨平台数据交互等领域。
在本文中,我们将介绍序列化和反序列化的方式,包括手动序列化方法、自动序列化方法以及XML、JSON等格式的序列化方式。
手动序列化方法手动序列化是指通过编写代码手动将对象转化为字节流,然后将字节流写入磁盘或通过网络发送。
手动序列化需要开发人员手动控制每个属性的序列化和反序列化方式。
以下是一个Java类的手动序列化示例:```javaimport java.io.*;public class User implements Serializable {private String name;private int age;private static final long serialVersionUID = 1L;public User() {}public User(String name, int age) { = name;this.age = age;}public void writeObject(ObjectOutputStream objOut) throws IOException {objOut.writeObject(name);objOut.writeInt(age);}public void readObject(ObjectInputStream objIn) throws IOException, ClassNotFoundException {name = (String) objIn.readObject();age = objIn.readInt();}public static void main(String[] args) {User user = new User("Alice", 18);try {ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream("user.data"));user.writeObject(objOut);objOut.close();ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("user.data"));User newUser = new User();newUser.readObject(objIn);System.out.println( + " " + newUser.age); objIn.close();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}}```在这个Java类中,我们实现了Serializable接口,这使得对象可以被序列化。
java 对象序列化反序列化方法Java 对象的序列化和反序列化是指将对象转换为字节流,以便于存储或传输,然后再将字节流转换回对象的过程。
在 Java 中,可以使用Serializable 接口和ObjectInputStream、ObjectOutputStream 类来实现对象的序列化和反序列化。
一、对象序列化对象序列化是将对象转换为字节流的过程。
在 Java 中,要实现对象序列化,需要满足以下两个条件:1. 类必须实现 Serializable 接口:Serializable 接口是一个标记接口,没有任何方法。
通过实现 Serializable 接口,表明该类的对象可以被序列化。
2. 字段必须是可序列化的:如果一个类的字段是对象类型,那么该对象的类也必须实现 Serializable 接口才能被序列化。
实现对象序列化的步骤如下:1. 创建一个类,实现 Serializable 接口。
2. 在类中定义字段,用于存储对象的属性。
3. 在类中提供构造方法和访问方法。
4. 使用 ObjectOutputStream 类将对象序列化为字节流。
下面是一个示例代码,演示了如何实现对象序列化:```javaimport java.io.Serializable;public class Student implements Serializable { private String name;private int age;public Student(String name, int age) { = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}}import java.io.FileOutputStream;import java.io.ObjectOutputStream;public class SerializationDemo {public static void main(String[] args) {Student student = new Student("John", 20);try {FileOutputStream fileOut = new FileOutputStream("student.ser");ObjectOutputStream out = new ObjectOutputStream(fileOut);out.writeObject(student);out.close();fileOut.close();System.out.println("Serialized data is saved in student.ser");} catch (Exception e) {e.printStackTrace();}}}```在上述示例代码中,我们定义了一个Student 类,并实现了Serializable 接口。
Java对象序列化和反序列化(实现Serializable接⼝)序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种⽤途: 1)把对象的字节序列永久地保存到硬盘上,通常存放在⼀个⽂件中; 2)在⽹络上传送对象的字节序列。
JDK类库中的序列化API java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)⽅法可对参数指定的obj对象进⾏序列化,把得到的字节序列写到⼀个⽬标输出流中。
java.io.ObjectInputStream代表对象输⼊流,它的readObject()⽅法从⼀个源输⼊流中读取字节序列,再把它们反序列化为⼀个对象,并将其返回。
只有实现了Serializable和Externalizable接⼝的类的对象才能被序列化。
Externalizable接⼝继承⾃ Serializable接⼝,实现Externalizable接⼝的类完全由⾃⾝来控制序列化的⾏为, ⽽仅实现Serializable接⼝的类可以采⽤默认的序列化⽅式。
对象序列化包括如下步骤: 1)创建⼀个对象输出流,它可以包装⼀个其他类型的⽬标输出流,如⽂件输出流; 2)通过对象输出流的writeObject()⽅法写对象。
对象反序列化的步骤如下: 1)创建⼀个对象输⼊流,它可以包装⼀个其他类型的源输⼊流,如⽂件输⼊流; 2)通过对象输⼊流的readObject()⽅法读取对象。
⽰例:新建⼀个Car 类1package com.oukele.redis2.entity;23import java.io.Serializable;45public class Car implements Serializable {67/*8 * 编号9*/10private int id;11/*12 * 车名13*/14private String name;15/*16 * 车速17*/18private double speed;1920public Car(String name,double speed ){ = name;22this.speed = speed;23 }2425public Car(int id, String name, double speed) {26this.id = id; = name;28this.speed = speed;29 }3031public int getId() {32return id;33 }3435public void setId(int id) {36this.id = id;37 }3839public String getName() {40return name;41 }4243public void setName(String name) { = name;45 }4647public double getSpeed() {48return speed;49 }5051public void setSpeed(double speed) {52this.speed = speed;53 }5455 @Override56public String toString() {57return "Car{" +58 "id=" + id +59 ", name='" + name + '\'' +60 ", speed=" + speed +61 '}';62 }63 }新建⼀个 SerializeUtil 类(封装序列化和反序列化的⽅法,便于调⽤)1package com.oukele.redis2.util;23import java.io.ByteArrayInputStream;4import java.io.ByteArrayOutputStream;5import java.io.ObjectInputStream;6import java.io.ObjectOutputStream;78public class SerializeUtil {910/*11 * 序列化12 * */13public static byte[] serialize(Object object){14//序列化流(输出流) --> 表⽰向⼀个⽬标写⼊数据15 ObjectOutputStream objectOutputStream =null;16//字节数组输出流17 ByteArrayOutputStream byteArrayOutputStream = null;18try{19//创建⼀个缓冲区20 byteArrayOutputStream = new ByteArrayOutputStream();21//将对象序列化成字节后输⼊缓冲区中22 objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);23//序列化对象24 objectOutputStream.writeObject(object);25//得到序列化字节26byte[] bytes = byteArrayOutputStream.toByteArray();2728//清空输出流29 objectOutputStream.flush();30//释放资源31 objectOutputStream.close();3233return bytes;34 }catch (Exception e){35 System.out.println("出现异常:"+e.getMessage());36 }37return null;38 }3940/*41 * 反序列化42 * */4344public static <T> T deserialize(byte[] bytes,Class<T> clazz){45//字节数组46 ByteArrayInputStream byteArrayInputStream = null;47try{48//将得到的序列化字节丢进缓冲区49 byteArrayInputStream = new ByteArrayInputStream(bytes);50//反序列化流(输⼊流)--> 表⽰着从⼀个源头读取数据,(读取缓冲区中的字节)51 ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 52//反序化成⼀个对象53return (T)objectInputStream.readObject();54 }catch (Exception e){55 System.out.println("出现异常:"+e.getMessage());56 }57return null;58 }596061 }测试:1 //序列化⼀个对象2 byte[] serialize = SerializeUitl.serialize(new Car(2,"宝马",88.8));3 //反序列化4 Car deserialize = SerializeUitl.deserialize(serialize, Car.class);5 System.out.println(deserialize);测试结果:⽰例源码地址:。