java序列化与反序列化系列问题

1.Serializable 实现序列化

1.定义 把 Java 对象转换为字节序列的过程称为对象的序列化。 把字节序列恢复为 Java 对象的过程称为对象的反序列化。

2.实现方式 所有实现序列化的类都必须实现 Serializable 接口,它是一种标记接口,里面没有任 何方法。
实现Java对象序列化与反序列化的方法
假定一个Student类,它的对象需要序列化,可以有如下三种方法:
方法一:若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化
ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对对Student对象的非transient的实例变量进行反序列化。

方法二:若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。

import java.io.Serializable;  

/** 
 *Title:学生类 
 *Description:实现序列化接口的学生类 
 *Copyright: copyright(c) 2012 
 *Filename: Student.java 
 *@author Wang Luqing 
 *@version 1.0 
 */  
public class Student implements Serializable  
{  
 private String name;  
 private char sex;  
 private int year;  
 private double gpa;  

 public Student()  
 {  

 }  
 public Student(String name,char sex,int year,double gpa)  
 {  
  this.name = name;  
  this.sex = sex;  
  this.year = year;  
  this.gpa = gpa;  
 }  

 public void setName(String name)  
 {  
  this.name = name;  
 }  

 public void setSex(char sex)  
 {  
  this.sex = sex;  
 }  

 public void setYear(int year)  
 {  
  this.year = year;  
 }  

 public void setGpa(double gpa)  
 {  
  this.gpa = gpa;  
 }  

 public String getName()  
 {  
  return this.name;  
 }  

 public char getSex()  
 {  
  return this.sex;  
 }  

 public int getYear()  
 {  
  return this.year;  
 }  

 public double getGpa()  
 {  
  return this.gpa;  
 }  
}  


import java.io.*;  

/** 
 *Title:应用学生类 
 *Description:实现学生类实例的序列化与反序列化 
 *Copyright: copyright(c) 2012 
 *Filename: UseStudent.java 
 *@author Wang Luqing 
 *@version 1.0 
 */  

public class UseStudent  
{  
 public static void main(String[] args)  
 {  
  Student st = new Student("Tom",'M',20,3.6);  
  File file = new File("O:\\Java\\com\\jieke\\io\\student.txt");  
  try  
  {  
   file.createNewFile();  
  }  
  catch(IOException e)  
  {  
   e.printStackTrace();  
  }  
  try  
  {  
   //Student对象序列化过程  
   FileOutputStream fos = new FileOutputStream(file);  
   ObjectOutputStream oos = new ObjectOutputStream(fos);  
   oos.writeObject(st);  
   oos.flush();  
   oos.close();  
   fos.close();  

   //Student对象反序列化过程  
   FileInputStream fis = new FileInputStream(file);  
   ObjectInputStream ois = new ObjectInputStream(fis);  
   Student st1 = (Student) ois.readObject();  
   System.out.println("name = " + st1.getName());  
   System.out.println("sex = " + st1.getSex());  
   System.out.println("year = " + st1.getYear());  
   System.out.println("gpa = " + st1.getGpa());  
   ois.close();  
   fis.close();  
  }  
  catch(ClassNotFoundException e)  
  {  
   e.printStackTrace();  
  }  
  catch (IOException e)  
  {  
   e.printStackTrace();  
  }               
 }  
}  
2.序列号相关特点

3.1 序列化时,只对对象的状态进行保存,而不管对象的方法。
3.2 当一个父类实现序列化时,子类自动实现序列化,不需要显示实现 Serializable 接口。
3.3 当一个对象的实例变量引用了其他对象时,序列化该对象时,也把引用对象进行序列 化。
3.4 对象中被 static 或者 transient 修饰的变量,在序列化时其变量值是不被保存的。
4.好处

3.相关问题

1)Java中的Serializable接口和Externalizable接口有什么区别?
这个是面试中关于Java序列化问的最多的问题。我的回答是Externalizable 接口提供了两个方法 writeExternal()和readExternal()。这两个方法给我们提供了灵活处理Java序列化的方法,通过实现这个接口中的两个方法进行对象序列化可以替代Java中默认的序列化方法。正确的实现Externalizable接口可以大幅度的提高应用程序的性能。

2)Serializable接口中有几个方法?如果没有方法的话,那么这么设计Serializable接口的目的是什么?
Serializable接口在java.lang包中,是Java序列化机制的核心组成部分。它里面没有包含任何方法,我们称这样的接口为标识接口。如果你的类实现了Serializable接口,这意味着你的类被打上了“可以进行序列化”的标签,并且也给了编译器指示,可以使用序列化机制对这个对象进行序列化处理。

3)什么是serialVersionUID?如果你没有定义serialVersionUID意味着什么?
SerialVersionUID应该是你的类中的一个publicstatic final类型的常量,如果你的类中没有定义的话,那么编译器将抛出警告。如果你的类中没有制定serialVersionUID,那么Java编译器会根据类的成员变量和一定的算法生成用来表达对象的serialVersionUID ,通常是用来表示类的哈希值(hash code)。结论是,如果你的类没有实现SerialVersionUID,那么如果你的类中如果加入或者改变成员变量,那么已经序列化的对象将无法反序列化。这是因为,类的成员变量的改变意味这编译器生成的SerialVersionUID的值不同。Java序列化过程是通过正确SerialVersionUID来对已经序列化的对象进行状态恢复

4)当对象进行序列化的时候,如果你不希望你的成员变量进行序列化,你怎么办?
这个问题也会这么问,如何使用暂态类型的成员变量?暂态和静态成员变量是否会被序列化等等。如果你不希望你的对象中的成员变量的状态得以保存,你可以根据需求选择transient或者static类型的变量,这样的变量不参与Java序列化处理的过程。

6)如果一个类是可序列化的,而他的超类没有,那么当进行反序列化的时候,那些从超类继承的实例变量的值是什么?
Java中的序列化处理实例变量只会在所有实现了Serializable接口的继承支路上展开。所以当一个类进行反序列化处理的时候,超类没有实现Serializable接口,那么从超类继承的实例变量会通过为实现序列化接口的超类的构造函数进行初始化

8)假设一个新的类的超类实现了Serializable接口,那么如何让这个新的子类不被序列化?
如果一个超类已经序列化了,那么无法通过是否实现什么接口的方式再避免序列化的过程了,但是也还有一种方式可以使用。那就是需要你在你的类中重新实现writeObject()和readObject()方法,并在方法实现中通过抛出NotSerializableException。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值