JAVA对象的序列化与反序列化(详细)

上传人:li****i 文档编号:243141358 上传时间:2024-09-16 格式:PPT 页数:41 大小:101.50KB
返回 下载 相关 举报
JAVA对象的序列化与反序列化(详细)_第1页
第1页 / 共41页
JAVA对象的序列化与反序列化(详细)_第2页
第2页 / 共41页
JAVA对象的序列化与反序列化(详细)_第3页
第3页 / 共41页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,第一级,第二级,*,对象的序列化与反序列化,主要内容,概述,当两个进程进行远程通信时,彼此可以发送各种类型的数据,包括文本,图片,音频,视频等,都会以二进制序列的形式在网络上传送,.,当两个,java,进程进行通信时,一个进程能否把一个,java,对象发送给另一个进程呢,?,答案是肯定的,!,概述,如何才能做到呢,1),发送方需要把这个,java,对象转换为字节序列,才能在网上传送,2),接收方需要把字节序列再恢复为,java,对象,.,把,java,对象转换为字节序列的过程称为对象的序列化,.,把字节序列恢复为,java,对象的过程称为对象的反序列化,.,序列化与反序列化,对象序列化两种用途,把对象的字节序列永久的保存到硬盘上,通常存放在一个文件中,.,在网络上传送对象的字节序列,.,主机,1,主机,2,文件,网络传输,存储到文件,9.1.jdk,类库中的序列化,API,如何才能做到呢,1),发送方需要把这个,java,对象转换为字节序列,才能在网上传送,2),接收方需要把字节序列再恢复为,java,对象,.,把,java,对象转换为字节序列的过程称为对象的序列化,.,把字节序列恢复为,java,对象的过程称为对象的反序列化,.,序列化与反序列化,9.1jdk,类库中的序列化,API,java.io.ObjectOutputStream,:,代表对象输出流,它的,writeObject(Object,obj,),方法可对参数指定的,obj,对象进行序列化,把得到的字节序列写到一个目标输出流中。,Java.io.ObjectInputStream,代表对象输入流,,它的,readObject,(),方法从一个源输入流中读取字节,再把它们反序列化成一个对象,并将其返回。,9.1jdk,类库中的序列化,API,哪些类可以被序列化呢?,只有实现了,Serializable,或,Externalizable,接口的类的对象才能被序列化,否则,ObjectOutputStream,的,writeObject(Object,obj,),方法会抛出,IOException,。,实现了,Serializable,或,Externalizable,接口的类也称为可序列化类。,Externalizable,接口继承,Serializable,接口,实现,Externalizable,接口的类完全由自身来控制序列化的行为。而仅实现,Serializable,接口的类可以采用默认的序列化方式。,Jdk,的部分类 如,StringDate,等都实现了,Serializable,接口,9.1jdk,类库中的序列化,API,假定一个,Customer,类,它的对象需要序列化。 可以有以下三种方式进行,如果,customer,类仅仅实现了,Serializable,接口的类,那么会按照以下方式进行序列化和反序列化:,ObjectOutputStream,采用默认的序列化方式,对,Customer,对象的非,transient,的实例变量进行序列化。,ObjectInputStream,采用默认的反序列化方式,对,customer,对象的非,transient,的实例变量进行反序列化。,9.1jdk,类库中的序列化,API,2.,如果,customer,类仅仅实现了,Serializable,接口,并且还定义了,readObject(ObjectInputStream,in),和,writeObject(ObjectOutputStream,out),那么会按照以下方式进行序列化和反序列化:,ObjectOutputStream,会调用,Customer,对象的,writeObject(ObjectOutputStream,out),方法进行序列化。,ObjectInputStream,会调用,Customer,对象的,readObject(ObjectInputStream,in),方法进行反序列化。,9.1jdk,类库中的序列化,API,3.,如果,customer,类实现了,Externalizable,接口,那么,Customer,类必须实现,readExternal(ObjectInput,in),和,writeExternal(ObjectOutput,out),方法,那么会按照以下方式进行序列化和反序列化:,ObjectOutputStream,会调用,Customer,对象的,writeExternal(ObjectOutput,out),方法进行序列化。,ObjectInputStream,会调用,Customer,对象的,readExternal(ObjectInput,in),方法进行反序列化。,9.1jdk,类库中的序列化,API,类框图,9.1jdk,类库中的序列化步骤,创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流:,ObjectOutputStream,out = new,ObjectOutputStream(new,fileOutputStream(“D:objectfile.obj,”);,9.1jdk,类库中的序列化步骤,通过对象输出流的,writeObject,(),方法写对象,如:,Out.writeObject(“hello,”);,Out.writeObject(new,Date();,9.1jdk,类库中的反序列化步骤,创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流:,ObjectInputStream,in = new,ObjectInputStream,(new,fileIutputStream(“D:objectfile.obj,”);,9.1jdk,类库中的反序列化步骤,通过对象输入流的,readObject,(),方法读取对象,如:,String obj1=(,String)in.readObject,();,Date obj2=(,Date)in.readObject,();,为了能正确读取数据,必须保证向对象输出流写对象的顺序与从对象输入流读对象的顺序一致,例,9.1jdk,类库中序列化程序,import,java.io,.*;import,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.writeObject(obj2);,out.writeObject(obj3);,out.writeInt(123);,out.close,();,例,9.1jdk,类库中序列化程序,/,反序列化对象,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 = (,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,();,例,9.1jdk,类库中序列化程序,class Customer implements,Serializable,private String name;,private,int,age;,public,Customer(String,name,int,age),this.name,=name;,this.age,=age;,public String,toString()return,name=+,name+,age,=+age;,例程,9-2,SimpleServer,该服务器从命令行读取用户指定的类名,创建该类的一个对象,然后向客户端两次发送这个对象。,结果表明:按照默认方式序列化时,如果有一个,ObjectOutputStream,对象多次序列化同一个对象,那么有一个,ObjectInputStream,对象反序列化出来的对象也是同一个对象。,例程,9-2,SimpleServer,import,java.io,.*;import,.*;import,java.util,.*;,public class,SimpleServer,public void,send(Object,object)throws,IOException,ServerSocket,serverSocket,= new ServerSocket(8000);,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,();, ,例程,9-2,SimpleServer,public static void,main(String,args)throws,IOException,Object,object,=null;,if(args.length,0 & args0.equals(Date),object=new Date();,else,if(args.length,0 & args0.equals(Customer1),object=new Customer1(Tom,1234);,else,if(args.length,0 & args0.equals(Customer2),Customer2 customer=new Customer2(Tom);,Order2 order1=new Order2(number1,customer);,Order2,order2,=new Order2(number2,customer);,customer.addOrder(order1);,customer.addOrder(order2);,object=customer;,例程,9-2,SimpleServer,else,if(args.length,0 & args0.equals(Customer3),object=new Customer3(Tom,1234);,else,if(args.length,0 & args0.equals(Customer4),Customer4 customer=new Customer4(Tom);,Order4 order1=new Order4(number1,customer);,Order4 order2=new Order4(number2,customer);,customer.addOrder(order1);,customer.addOrder(order2);,object=customer;,else,if(args.length,0 & args0.equals(Customer5),object=new Customer5(Tom,25);,else object=Hello; ,System.out.println,(,待发送的对象信息:,+object);,new,SimpleServer().send(object,);,例程,9-3,SimpleClient,import,java.io,.*;import,.*;import,java.util,.*;,public class,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(object2);,System.out.println(object1,与,object2,是否为同一个对象,:,+(object1=object2); ,public static void,main(String,args)throws,Exception ,new,SimpleClient().receive,(); ,9.2,实现,Serializable,接口,ObjectOutputStream,只能对实现了,Serializable,接口的类的对象进行序列化,,默认情况下,,ObjectOutputStream,按照默认方式进行序列化,这种方式只能对对象的非,transient,的实例变量进行序列化,而不会序列化对象的,transient,的实例变量和静态变量,例如例程,9-4,9.2,实现,Serializable,接口,public class Customer1 implements,Serializable,private static,int,count; /,用于计算Customer对象的数目,private static final,int,MAX_COUNT=1000;,private String name;,private transient String password;,static System.out.println(调用Customer1类的静态代码块); ,public Customer1(),System.out.println(调用Customer1类的不带参数的构造方法);,count+; ,public Customer1(String name, String password) ,System.out.println(调用Customer1类的带参数的构造方法);,this.name,=name;,this.password,=password; count+; ,public String,toString,() ,return count=+count + MAX_COUNT=+MAX_COUNT,+ name=+name + password=+ password; ,9.2,实现,Serializable,接口,先运行,”,java,SimpleServer,Customer1”,再运行命令“,java,SimpleClient,”,服务器端打印的结果如下:,调用,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 name=Tom password=null,Object1,与,Object2,是否为同一个对象:,true,9.2,实现,Serializable,接口,先运行,”,java,SimpleServer,Customer1”,再运行命令“,java,SimpleClient,”,服务器端打印的结果如下:,调用,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 name=Tom password=null,Object1,与,Object2,是否为同一个对象:,true,9.3,序列化对象图,类与类之间可能存在关联关系。如例程,9-5,,,customer2,与,order2,之间存在一对多的双向关联关系,9.3,序列化对象图,public class Customer2 implements,Serializable,private String name;,private Set orders=new,HashSet,();,static,System.out.println,(,调用,Customer2,类的静态代码块,); ,public Customer2(),System.out.println,(,调用,Customer2,类的不带参数的构造方法,); ,public Customer2(String name) ,System.out.println,(,调用,Customer2,类的带参数的构造方法,);,this.name,=name; ,public void addOrder(Order2 order),orders.add(order,); ,public String,toString,() ,String result=,super.toString()+rn+orders+rn,;,return result; ,9.3,序列化对象图,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;,this.customer,=customer;,9.3,序列化对象图,在例程,9-2,中以下代码建立了他们的关联关系:,else,if(args.length,0 & args0.equals(Customer2),Customer2 customer=new Customer2(Tom);,Order2 order1=new Order2(number1,customer);,Order2,order2,=new Order2(number2,customer);,customer.addOrder(order1);,customer.addOrder(order2);,object=customer;,Customer2,对象,Order2,对象,Order2,对象,9.3,序列化对象图,序列化,customer2,对象时是否会序列化与它关联的对象呢?,序列化对象时,会序列化对象,customer2,以及所有从,customer2,直接或间接导航到的对象。,Customer2,对象,Order2,对象,Order2,对象,9,。,2,。,2,控制序列化的行为,如果用户希望控制序列化行为,可以在序列化类中提供以下方法:,private void,writeObject(ObjectOutputStream,ou,),在该方法中可以调用,ObjectOutputStream,拥有的,defaultWriteObject(ObjectOutputStream,ou,),,使得对象输出流先执行默认的序列化操作,private void,readObject(ObjectInputStream,in),在该方法中同样可以调用,ObjectInputStream,的,defaultReadObject,(),方法。,9,。,2,。,2,控制序列化的行为,以下情况下,可以考虑用户自定义的序列化方式,从而控制序列化行为:,确保序列化安全性,对敏感信息加密后再序列化,反序列化时需解密。,确保对象的成员变量符合正确的约束条件,优化序列化的性能。,便于更好的封装类的内部数据结构,确保类的接口不会被类的内部实现所束缚,9.2.2,控制序列化的行为,import,java.io,.*;,public class Customer3 implements,Serializable,private static,int,count; /,用于计算,Customer3,对象的数目,private static final,int,MAX_COUNT=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,类的带参数的构造方法,);,this.name,=name;,this.password,=password;,count+; ,序列化的安全性,9,。,2,。,2,控制序列化的行为,/*,加密数组,将,buff,数组中的每个字节的每一位取反,* 例如,13,的二进制为,00001101,,取反后为,11110010,*/,private byte,change(byte, buff),for(int,i=0;i,buff.length;i,+),int,b=0;,for(int,j=0;jj ,b+=(1j)*bit;,buffi,=(,byte)b,;,return buff;,9.2.2,控制序列化的行为,private void,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,();,9.2.2,控制序列化的行为,9-7,public class Customer implements,Serializable,private,int,age;,public,Customer(int,age) ,if(age,0) /,合法性检查,throw new,IllegalArgumentException(年龄不能小于零,);,this.age,=age; ,public String,toString,() ,return age=+age; ,private void,readObject(ObjectInputStream,stream),throws,IOException,ClassNotFoundException,stream.defaultReadObject,(); /,先按默认方式反序列化,if(age,0) /,合法性检查,throw new,IllegalArgumentException(年龄不能小于零,); ,确保对象的成员变量符合正确的约束条件,9.2.2,控制序列化的行为,public static void,main(String,args,) throws Exception,Customer,customer,= new Customer(25);,System.out.println(Before,Serialization: + customer);,ByteArrayOutputStream,buf,= new,ByteArrayOutputStream,();,/,把Customer对象序列化到一个字节缓存中,ObjectOutputStream,o =new,ObjectOutputStream(buf,);,o.writeObject(customer,);,byte,byteArray,=,buf.toByteArray,();,for(int,i=0;i,byteArray.length;i,+),System.out.print(byteArrayi,+ );,if(i,% 10=0 & i!=0) | i=byteArray.length-1),System.out.println,();,确保对象的成员变量符合正确的约束条件,9.2.2,控制序列化的行为,/,篡改序列化数据,byteArraybyteArray.length-4=-1;,byteArraybyteArray.length-3=-1;,byteArraybyteArray.length-2=-1;,byteArraybyteArray.length-1=-10;,/,从字节缓存中反序列化Customer对象,ObjectInputStream,in =new,ObjectInputStream,(,new,ByteArrayInputStream(byteArray,);,customer= (Customer)in.readObject();,/-10,System.out.println(After,Serialization: + customer);,确保对象的成员变量符合正确的约束条件,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 小学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!