对象的序列化与反序列化_第1页
对象的序列化与反序列化_第2页
对象的序列化与反序列化_第3页
对象的序列化与反序列化_第4页
对象的序列化与反序列化_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 当两个进程进行远程通信时当两个进程进行远程通信时,彼此可以发送各彼此可以发送各 种类型的数据种类型的数据,包括文本包括文本图片图片音频音频视频等视频等,都都 会以二进制序列的形式在网络上传送会以二进制序列的形式在网络上传送. 当两个当两个java进程进行通信时进程进行通信时,一个进程能否把一一个进程能否把一 个个java对象发送给另一个进程呢对象发送给另一个进程呢? 答案是肯定的答案是肯定的! 如何才能做到呢如何才能做到呢 1)发送方需要把这个发送方需要把这个java对象转换为字节序列对象转换为字节序列, 才能在网上传送才能在网上传送 2)接收方需要把字节序列再恢复为接收方需要把字节序列再恢

2、复为java对象对象. 把把java对象转换为字节序列的过程称为对象的对象转换为字节序列的过程称为对象的 序列化序列化,. 把字节序列恢复为把字节序列恢复为java对象的过程称为对象的对象的过程称为对象的 反序列化反序列化. 序列化与反序列化序列化与反序列化 把对象的字节序列永久的保存到硬盘上,把对象的字节序列永久的保存到硬盘上, 通常存放在一个文件中通常存放在一个文件中. 在网络上传送对象的字节序列在网络上传送对象的字节序列. 主机1主机2 文件 网络传输 存储到文件 如何才能做到呢如何才能做到呢 1)发送方需要把这个发送方需要把这个java对象转换为字节序列对象转换为字节序列, 才能在网上

3、传送才能在网上传送 2)接收方需要把字节序列再恢复为接收方需要把字节序列再恢复为java对象对象. 把把java对象转换为字节序列的过程称为对象的对象转换为字节序列的过程称为对象的 序列化序列化,. 把字节序列恢复为把字节序列恢复为java对象的过程称为对象的对象的过程称为对象的 反序列化反序列化. 序列化与反序列化序列化与反序列化 java.io.ObjectOutputStream:代表对象输出流 它的writeObject(Object obj)方法可对参数指定的obj对 象进行序列化,把得到的字节序列写到一个目标输 出流中。 Java.io.ObjectInputStream代表对象输

4、入流, 它的readObject()方法从一个源输入流中读取字节, 再把它们反序列化成一个对象,并将其返回。 哪些类可以被序列化呢? 只有实现了Serializable或Externalizable接口的类的对 象才能被序列化,否则ObjectOutputStream的 writeObject(Object obj)方法会抛出IOException。 实现了Serializable或Externalizable接口的类也称为可 序列化类。 Externalizable接口继承Serializable接口,实现 Externalizable接口的类完全由自身来控制序列化的行 为。而仅实现Seri

5、alizable接口的类可以采用默认的 序列化方式。 Jdk的部分类 如StringDate等都实现了Serializable接口 假定一个Customer类,它的对象需要序列化。 可以 有以下三种方式进行 如果customer类仅仅实现了Serializable接口的类,那 么会按照以下方式进行序列化和反序列化: ObjectOutputStream采用默认的序列化方式,对 Customer对象的非transient的实例变量进行序列化。 1.ObjectInputStream采用默认的反序列化方式,对 customer对象的非transient的实例变量进行反序列化。 2. 如果custo

6、mer类仅仅实现了Serializable接口,并 且还定义了readObject(ObjectInputStream in)和 writeObject(ObjectOutputStream out),那么会按照 以下方式进行序列化和反序列化: ObjectOutputStream会调用Customer对象的 writeObject(ObjectOutputStream out)方法进行序 列化。 ObjectInputStream会调用Customer对象的 readObject(ObjectInputStream in)方法进行反序列 化。 3. 如果customer类实现了Externa

7、lizable接口,那么 Customer类必须实现readExternal(ObjectInput in) 和writeExternal(ObjectOutput out)方法,那么会 按照以下方式进行序列化和反序列化: ObjectOutputStream会调用Customer对象的 writeExternal(ObjectOutput out)方法进行序列化。 ObjectInputStream会调用Customer对象的 readExternal(ObjectInput in)方法进行反序列化。 创建一个对象输出流,它可以包装一个其创建一个对象输出流,它可以包装一个其 他类型的目标输出

8、流,如文件输出流:他类型的目标输出流,如文件输出流: ObjectOutputStream out = new ObjectOutputStream(new fileOutputStream(“D:objectfile.obj”); 通过对象输出流的通过对象输出流的writeObject()方法写对象,方法写对象, 如:如: Out.writeObject(“hello”); Out.writeObject(new Date(); 创建一个对象输入流,它可以包装一个其创建一个对象输入流,它可以包装一个其 他类型的源输入流,如文件输入流:他类型的源输入流,如文件输入流: ObjectInputS

9、tream in = new ObjectInputStream (new fileIutputStream(“D:objectfile.obj”); 通过对象输入流的通过对象输入流的readObject()方法读取对方法读取对 象,如:象,如: String obj1=(String)in.readObject(); Date obj2=(Date)in.readObject(); 为了能正确读取数据,必须保证向对象输为了能正确读取数据,必须保证向对象输 出流写对象的顺序与从对象输入流读对象出流写对象的顺序与从对象输入流读对象 的顺序一致的顺序一致 import java.io.*;impo

10、rt java.util.*; public class ObjectSaver public static void main(String agrs) throws Exception ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream(D:objectFile.obj); String obj1=hello; Date obj2=new Date(); Customer obj3=new Customer(Tom,20); /序列化对象序列化对象 out.writeObject(obj1); out.wri

11、teObject(obj2); out.writeObject(obj3); out.writeInt(123); out.close(); /反序列化对象反序列化对象 ObjectInputStream in=new ObjectInputStream(new FileInputStream(D:objectFile.obj); String obj11 = (String)in.readObject(); System.out.println(obj11:+obj11); System.out.println(obj11=obj1:+(obj11=obj1); Date obj22 = (

12、Date)in.readObject(); System.out.println(obj22:+obj22); System.out.println(obj22=obj2:+(obj22=obj2); Customer obj33 = (Customer)in.readObject(); System.out.println(obj33:+obj33); System.out.println(obj33=obj3:+(obj33=obj3); int var= in.readInt(); System.out.println(var:+var); in.close(); class Custo

13、mer implements Serializable private String name; private int age; public Customer(String name,int age) =name; this.age=age; public String toString()return name=+name+,age=+age; 该服务器从命令行读取用户指定的类名,该服务器从命令行读取用户指定的类名, 创建该类的一个对象,然后向客户端两次创建该类的一个对象,然后向客户端两次 发送这个对象。发送这个对象。 结果表明:按照默认方式序列化时,如果结果表明:按照

14、默认方式序列化时,如果 有一个有一个ObjectOutputStream对象多次序列化同对象多次序列化同 一个对象,那么有一个一个对象,那么有一个ObjectInputStream对对 象反序列化出来的对象也是同一个对象。象反序列化出来的对象也是同一个对象。 import java.io.*;import .*;import java.util.*; public class SimpleServer public void send(Object object)throws IOException ServerSocket serverSocket = new ServerSocket(80

15、00); while(true) Socket socket=serverSocket.accept(); OutputStream out=socket.getOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(out); oos.writeObject(object); oos.writeObject(object); oos.close(); socket.close(); public static void main(String args)throws IOException Object object=nul

16、l; if(args.length0 else if(args.length0 else if(args.length0 Order2 order1=new Order2(number1,customer); Order2 order2=new Order2(number2,customer); customer.addOrder(order1); customer.addOrder(order2); object=customer; else if(args.length0 else if(args.length0 Order4 order1=new Order4(number1,custo

17、mer); Order4 order2=new Order4(number2,customer); customer.addOrder(order1); customer.addOrder(order2); object=customer; else if(args.length0 else object=Hello; System.out.println(待发送的对象信息:待发送的对象信息:+object); new SimpleServer().send(object); import java.io.*;import .*;import java.util.*; public class

18、 SimpleClient public void receive()throws Exception Socket socket = new Socket(localhost,8000); InputStream in=socket.getInputStream(); ObjectInputStream ois=new ObjectInputStream(in); Object object1=ois.readObject(); Object object2=ois.readObject(); System.out.println(object1); System.out.println(o

19、bject2); System.out.println(object1与与object2是否为同一个对象是否为同一个对象: +(object1=object2); public static void main(String args)throws Exception new SimpleClient().receive(); ObjectOutputStream只能对实现了只能对实现了Serializable 接口的类的对象进行序列化,接口的类的对象进行序列化, 默认情况下,默认情况下, ObjectOutputStream按照默认按照默认 方式进行序列化,这种方式只能对对象的方式进行序列化

20、,这种方式只能对对象的 非非transient的实例变量进行序列化,而不会的实例变量进行序列化,而不会 序列化对象的序列化对象的transient的实例变量和静态变的实例变量和静态变 量,例如例程量,例如例程9-4 public class Customer1 implements Serializable private static int count; /用于计算用于计算Customer对象的数目对象的数目 private static final int MAX_COUNT=1000; private String name; private transient String pass

21、word; static System.out.println(调用调用Customer1类的静态代码块类的静态代码块); public Customer1() System.out.println(调用调用Customer1类的不带参数的构造方法类的不带参数的构造方法); count+; public Customer1(String name, String password) System.out.println(调用调用Customer1类的带参数的构造方法类的带参数的构造方法); =name; this.password=password; count+; publ

22、ic String toString() return count=+count + MAX_COUNT=+MAX_COUNT + name=+name + password=+ password; 先运行先运行”java SimpleServer Customer1”,再运行命令再运行命令 “java SimpleClient ”,服务器端打印的结果如下:服务器端打印的结果如下: 调用调用Customer1类的静态代码块类的静态代码块 调用调用Customer1类的带参数的构造方法类的带参数的构造方法 待发送的对象信息:待发送的对象信息:count=1 MAX_COUNT=1000 name

23、=Tom password=1234 客户端打印的信息(反序列化时不会调用类的构客户端打印的信息(反序列化时不会调用类的构 造方法)造方法) 调用调用Customer1类的静态代码块类的静态代码块 count=0 MAX_COUNT=1000 name=Tom password=null count=0 MAX_COUNT=1000 name=Tom password=null Object1与与Object2是否为同一个对象:是否为同一个对象:true 先运行先运行”java SimpleServer Customer1”,再运行命令再运行命令 “java SimpleClient ”,服务

24、器端打印的结果如下:服务器端打印的结果如下: 调用调用Customer1类的静态代码块类的静态代码块 调用调用Customer1类的带参数的构造方法类的带参数的构造方法 待发送的对象信息:待发送的对象信息:count=1 MAX_COUNT=1000 name=Tom password=1234 客户端打印的信息(反序列化时不会调用类的构客户端打印的信息(反序列化时不会调用类的构 造方法)造方法) 调用调用Customer1类的静态代码块类的静态代码块 count=0 MAX_COUNT=1000 name=Tom password=null count=0 MAX_COUNT=1000 na

25、me=Tom password=null Object1与与Object2是否为同一个对象:是否为同一个对象:true 类与类之间可能存在关联关系。如例程类与类之间可能存在关联关系。如例程9-5, customer2与与order2之间存在一对多的双向关之间存在一对多的双向关 联关系联关系 public class Customer2 implements Serializable private String name; private Set orders=new HashSet(); static System.out.println(调用调用Customer2类的静态代码块类的静态代码

26、块); public Customer2() System.out.println(调用调用Customer2类的不带参数的构造方法类的不带参数的构造方法); public Customer2(String name) System.out.println(调用调用Customer2类的带参数的构造方法类的带参数的构造方法); =name; public void addOrder(Order2 order) orders.add(order); public String toString() String result=super.toString()+rn+orders

27、+rn; return result; class Order2 implements Serializable private String number; private Customer2 customer; public Order2() System.out.println(调用调用Order2类的不带参数的构类的不带参数的构 造方法造方法); public Order2(String number,Customer2 customer) System.out.println(调用调用Order2类的带参数的构造类的带参数的构造 方法方法); this.number=number;

28、this.customer=customer; 在例程在例程9-2中以下代码建立了他们的关联关系:中以下代码建立了他们的关联关系: else if(args.length0 Order2 order1=new Order2(number1,customer); Order2 order2=new Order2(number2,customer); customer.addOrder(order1); customer.addOrder(order2); object=customer; Customer2对象 Order2对象 Order2对象 序列化序列化customer2对象时是否会序列化

29、与它对象时是否会序列化与它 关联的对象呢?关联的对象呢? 序列化对象时,会序列化对象序列化对象时,会序列化对象customer2以以 及所有从及所有从customer2直接或间接导航到的对直接或间接导航到的对 象。象。 Customer2对象 Order2对象 Order2对象 如果用户希望控制序列化行为,可以在序列化如果用户希望控制序列化行为,可以在序列化 类中提供以下方法:类中提供以下方法: private void writeObject(ObjectOutputStream ou) 在该方法中可以调用在该方法中可以调用ObjectOutputStream拥有的拥有的 defaultWr

30、iteObject(ObjectOutputStream ou),使得,使得 对象输出流先执行默认的序列化操作对象输出流先执行默认的序列化操作 private void readObject(ObjectInputStream in) 1.在该方法中同样可以调用在该方法中同样可以调用ObjectInputStream的的 defaultReadObject()方法。方法。 以下情况下,可以考虑用户自定义的序列以下情况下,可以考虑用户自定义的序列 化方式,从而控制序列化行为:化方式,从而控制序列化行为: 确保序列化安全性,对敏感信息加密后再确保序列化安全性,对敏感信息加密后再 序列化,反序列化时

31、需解密。序列化,反序列化时需解密。 确保对象的成员变量符合正确的约束条件确保对象的成员变量符合正确的约束条件 优化序列化的性能。优化序列化的性能。 1.便于更好的封装类的内部数据结构,确保便于更好的封装类的内部数据结构,确保 类的接口不会被类的内部实现所束缚类的接口不会被类的内部实现所束缚 import java.io.*; public class Customer3 implements Serializable private static int count; /用于计算用于计算Customer3对象的数目对象的数目 private static final int MAX_COUNT

32、=1000; private String name; private transient String password; static System.out.println(调用调用Customer3类的静态代码块类的静态代码块); public Customer3() System.out.println(调用调用Customer3类的不带参数的构造方法类的不带参数的构造方法); count+; public Customer3(String name, String password) System.out.println(调用调用Customer3类的带参数的构造方法类的带参数的构造

33、方法); =name; this.password=password; count+; 序列化的序列化的 安全性安全性 /* 加密数组,将加密数组,将buff数组中的每个字节的每一位取反数组中的每个字节的每一位取反 * 例如例如13的二进制为的二进制为00001101,取反后为,取反后为11110010 */ private byte change(byte buff) for(int i=0;ibuff.length;i+) int b=0; for(int j=0;jj b+=(1j)*bit; buffi=(byte)b; return buff; private vo

34、id writeObject(ObjectOutputStream stream)throws IOException stream.defaultWriteObject(); /先按默认方式序列化先按默认方式序列化 stream.writeObject(change(password.getBytes(); stream.writeInt(count); private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException stream.defaultReadObject(); /先按默认方式反序列化先按默认方式反序列化 byte buff=(byte)stream.readObject(); password = new String(change(buff); count=stream.readInt(); public class Customer implements Serializable private int age; public Customer(int age) if(age0) /合法性检查合法性检查 throw new IllegalArgumentException(年龄不能小于零年龄不能小于零); this.age=age;

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论