java 对象序列化和反序列化的性能,java中的序列化与反序列化

  java 对象序列化和反序列化的性能,java中的序列化与反序列化

  如何解决写爬虫IP受阻的问题?立即使用。

  对象的序列化和反序列化

  1)对象序列化是将对象转换成字节序列,反之亦然,称为对象反序列化。

  2)序列化流(ObjectOutputStream),这是字节过滤流的—— writeObject()方法。

  反序列化stream(objectinputstream)3354 read object()方法

  3)可串行化接口(Serializable)

  对象必须先实现序列化接口,然后才能序列化,否则将发生异常。

  注:这个接口,没有任何方法,只是一个【标准】

  一、最基本的序列化和反序列过程

  序列化和反序列化都是由Object对象操作的。这里用一个简单的案例来演示对象序列化和反序列化的过程。

  1、新建一个Student类(测试类)

  注意:序列化需要一个实现序列化接口的类!

  @SuppressWarnings(serial )

  公共类学生实现Serializable{

  私弦stuno//id

  私弦stuna//名称

  私立学校;//年龄

  公共字符串getStuno() {

  返回stuno

  }

  public void setStuno(String stuno){

  this.stuno=stuno

  }

  公共字符串getStuna() {

  返回stuna

  }

  public void setStuna(String stuna){

  this.stuna=stuna

  }

  公共学生(){

  super();

  //TODO自动生成的构造函数存根

  }

  public Student(String stuno,String stuna,int stuage) {

  super();

  this.stuno=stuno

  this.stuna=stuna

  this . stu age=stu age;

  }

  @覆盖

  公共字符串toString() {

  return Student [stuno= stuno ,stuna= stuna ,stu age= stu age ];

  }

  public int getStuage() {

  返程;

  }

  public void setStuage(int stuage){

  this . stu age=stu age;

  }

  }2、将Student类的实例序列化成文件

  基本操作步骤如下:

  1),指定序列化保存的文件。

  2)构造ObjectOutputStream类

  3)构建学生班级。

  4)使用writeObject方法的序列化

  5)使用close()方法关闭流。

  string file= demo/obj . dat ;

  //对象的序列化

  object output stream OOS=new object output stream(

  new file output stream(file));

  //保存学生对象,这是对象的序列化。

  学生stu=新生( 01 ,迈克,18);

  //使用writeObject方法序列化

  OOS . writeobject(stu);

  OOS . close();运行:可以看到在demo目录下生成了obj.dat的序列化文件。

  3、将文件反序列化读出Student类对象

  基本操作步骤如下:

  1),指定反序列化的文件。

  2)构造ObjectInputStream类

  3)使用readObject方法反序列化

  1)使用close方法关闭流。

  string file= demo/obj . dat ;

  ObjectInputStream ois=新的ObjectInputStream(

  new file inputstream(file));

  //用readObject()方法序列化

  学生stu=(学生)ois . read object();//strong制类型转换

  system . out . println(stu);

  ois . close();运行结果:

  注意:当文件被反序列化时,默认情况下,readObject方法检索的所有对象都是Object类型,并且必须转换为相应的类型。

  二、transient及ArrayList源码分析

  在日常编程过程中,我们有时不希望一个类的所有元素都被编译器序列化。那我们该怎么办?

  Java提供了一个transient关键字来修饰我们不希望被jvm自动序列化的元素。先简单解释一下这个关键词。

  transient 关键字:被transient修饰的元素,该元素不会进行jvm默认的序列化,但可以自己完成这个元素的序列化。

  注意:

  1)在以后的网络编程中,如果有一些不需要传输的元素,可以用transient来修饰,节省流量;序列化有效元素以提高性能。

  2)可以自己使用writeObject来序列化这个元素。

  ArrayList使用此方法来优化操作。ArrayList的核心容器Object[] elementData是用transient修饰的,但它的数组本身是在writeObject中序列化的。仅序列化数组中的有效元素。阅读是相似的。

  --------------自己序列化的方式---------------

  向要序列化的类中添加两个方法(这两个方法是从ArrayList源代码中提取的,是两个特殊的方法):

  private void writeObject(Java . io . object output stream s)抛出java.io.IOException{

  s . defaultwriteobject();//序列化jvm默认情况下可以序列化的元素

  s . write int(stu age);//自己完成transient修饰的元素的序列化

  }

  私有void read object(Java . io . objectinputstream s)抛出java.io.IOException,ClassNotFoundException{

  s . default read object();//反序列化jvm默认情况下可以反序列化的元素

  this . stu age=s . readint();//自己完成stuage的反序列化

  }添加这两个方法后,即使是transient修饰的元素也可以像刚才一样进行序列化和反序列化,jvm会自动使用这两个方法来帮助我们完成这个动作。

  还有一个问题。为什么需要手动完成序列化和反序列化?有什么意义?

  这个问题还得从ArrayList的源代码来分析:

  可以看出,ArrayList源代码中自序列化的目的是,ArrayList的底层是一个数组。自序列化可以过滤数组中的无效元素,只序列化数组中的有效元素,从而提高性能。

  因此,在实际编程过程中,我们可以根据需要自行完成序列化,以提高性能。

  三、序列化中子父类构造函数问题

  在一个类的序列化和反序列化中,如果子类和父类有关系,那么序列化和反序列化的过程是怎样的?

  这里我写一个测试类,测试子类和父类实现序列化和反序列化时构造函数的实现变化。

  公共静态void main(String[] args)引发IOException {

  //TODO自动生成的方法存根

  string file= demo/foo . dat ;

  object output stream OOS=new object output stream(

  new file output stream(file));

  foo 2 foo 2=new foo 2();

  OOS . writeobject(foo 2);

  OOS . flush();

  OOS . close();

  }

  }

  类Foo实现Serializable{

  公共Foo(){

  system . out . println( foo );

  }

  }

  类Foo1扩展了Foo{

  公共Foo1(){

  system . out . println( foo 1 );

  }

  }

  Foo2类扩展了Foo1{

  公共Foo2(){

  system . out . println( foo 2 );

  }

  }运行结果:这是序列化过程中递归调用父类的构造函数。

  我们来看看反序列化时是否递归调用了父类的构造函数。

  ObjectInputStream ois=新的ObjectInputStream(

  new file inputstream(file));

  foo 2 foo 2=(foo 2)ois . read object();

  ois . close();运行:控制台没有输出。

  那么这个结果是否证明了在反序列化过程中,从来不调用父类的构造函数呢?

  但是,无法证明!

  因为看下面不同的测试例子:

  类别栏{

  公共酒吧(){

  system . out . println( bar );

  }

  }

  Bar1类扩展Bar实现Serializable{

  公共栏1(){

  system . out . println( bar 1 );

  }

  }

  Bar2类扩展了Bar1{

  公共栏2(){

  system . out . println( bar 2 );

  }

  }我们用这个例子来测试序列化和反序列化。

  序列化结果:

  反序列化结果:显示未实现序列化接口的父类调用构造函数。

  【反序列化时】,递归调用构造函数up将从【可序列化的一级父类】开始结束。也就是说,谁实现了可序列化性(包括继承的实现),谁就不会调用它的构造函数。

  总结:

  1)父类实现serializable接口,子类继承可以序列化。

  当子类反序列化时,父类实现序列化接口,因此不会递归调用其构造函数。

  2)父类不实现serializable接口,子类可以自己实现serializable。

  当子类被反序列化时,如果父类没有实现序列化接口,它的构造函数将被递归调用。

  本文来自java入门专栏,欢迎学习!这就是Java对象的序列化和反序列化的细节。请多关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: