Java序列化机制

Java中对象序列化过程(序列化本身在.net和Java系列当中都有不同的实现,根据序列化格式的不同包含xml和二进制的序列化格式,在java.io.serializable进行二进制序列化):
Java序列化:
public class Test implements Serializable{

	/**
	 * @add by:  在原有代码基础上新增属性时需填写
	 */
	private static final long serialVersionUID = -3772479206916799373L;

	public static void main(String[] args) throws IOException{
		SerialTest st = new Test().new SerialTest();
		st.setName("name");
		st.setUID(1);
		
		File cf = new File("D:/dev/a.out");
		cf.createNewFile();
		FileOutputStream fis = new FileOutputStream(cf);
		ObjectOutputStream oop = new ObjectOutputStream(fis);
		oop.writeObject(st);
		oop.flush();
		oop.close();
	}
	
	private class SerialTest implements Serializable{

		/**
		 * @add by:  在原有代码基础上新增属性时需填写
		 */
		private static final long serialVersionUID = 7057425092293945310L;
		private String name;
		private Integer UID;
		
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public Integer getUID() {
			return UID;
		}
		public void setUID(Integer UID) {
			this.UID = UID;
		}
		
		public String toString(){
			return this.getName()+this.getUID();
		}
	}
}


Java反序列化:
public class Test implements Serializable{
	
	/**
	 * @add by:  在原有代码基础上新增属性时需填写
	 */
	private static final long serialVersionUID = -3772479206916799373L;

	public static void main(String[] args) throws IOException, ClassNotFoundException{

		File cf = new File("D:/dev/a.out");
		FileInputStream fis = new FileInputStream(cf);
		ObjectInputStream oop = new ObjectInputStream(fis);
		SerialTest st = (SerialTest)oop.readObject();
		System.out.println(st.toString());
	}
	
	private class SerialTest implements Serializable{
		
		/**
		 * @add by:  在原有代码基础上新增属性时需填写
		 */
		private static final long serialVersionUID = 7057425092293945310L;
		private String name;
		private Integer UID;
		
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public Integer getUID() {
			return UID;
		}
		public void setUID(Integer UID) {
			this.UID = UID;
		}
		public String toString(){
			return this.getName()+this.getUID();
		}
	}
}


序列化要点:
  • 作用--对象持久化,便于保存和传输。
  • 如果该类有父类,当其父类实现Serializable接口时,可以将父类属性序列化;如果没有实现Serializable接口,父类属性不被序列化;
  • 如果该属性被标示为static,则该属性不能被序列化;
  • transient关键字--表明当前属性不应被序列化,由于序列化将对象转换成字节流保存下来,比较耗费IO性能,涉及到以下情况时: 1、如果一些属性涉及到线程共享;2、需要访问IO、本地资源、网络资源等的属性;3、该属性为一个关联类,当该类没有实现Serializable接口并且未被标示为transient时,会报java.io.NotSerializableException异常;4、当A类为B类的非静态内部类时,对A序列化时,需要B也实现Serializable接口,否则会报java.io.NotSerializableException异常;
  • 序列化针对的内容是该对象的属性(即对象状态的载体),对象方法不会被序列化,方法信息可以通过对象加载后在保存Class信息的方法区取到;
  • 反序列化时的ClassLoader和序列化时的ClassLoader一致。
  • 序列化针对的是:对象的类,类签名,以及非瞬态和非静态字段的值。
  • 序列化操作不写出没有实现 java.io.Serializable 接口的任何对象的字段。不可序列化的 Object 的子类可以是可序列化的。在此情况下,不可序列化的类必须有一个无参数构造方法,以便允许初始化其字段。在此情况下,子类负责保存和还原不可序列化的类的状态。经常出现的情况是,该类的字段是可访问的(public、package 或 protected),或者存在可用来还原状态的 get 和 set 方法。
  • 实现 Externalizable 接口允许对象假定可以完全控制对象的序列化形式的内容和格式。调用 Externalizable 接口的方法(writeExternal 和 readExternal)来保存和恢复对象的状态。通过类实现时,它们可以使用 ObjectOutput 和 ObjectInput 的所有方法读写它们自己的状态。对象负责处理出现的任何版本控制。
  • 基本数据(不包括 serializable 字段和 externalizable 数据)以块数据记录的形式写入 ObjectOutputStream 中。块数据记录由头部和数据组成。块数据部分包括标记和跟在部分后面的字节数。连续的基本写入数据被合并在一个块数据记录中。块数据记录的分块因子为 1024 字节。每个块数据记录都将填满 1024 字节,或者在终止块数据模式时被写入。调用 ObjectOutputStream 方法 writeObject、defaultWriteObject 和 writeFields 最初只是终止所有现有块数据记录。

在序列化时,首先是将一个类的对象信息读取出来放入,按照一种约定格式转换成字节流的形式(以二进制的形式进行存储),持久化存入本地硬盘。
反序列化时,首先将对应的Class信息通过ClassLoader读取出来,在读取当前二进制流文件转换成当前对象对应的属性值。

序列化过程步骤:首先输出当前类的 元数据(在序列化一个对象时,通过序列化后得到的文件大小即可知道其中包含该对象的元数据信息,序列化后文件大小=对象状态数据+元数据+序列化格式信息),之后递归输出当前类的父类的元数据直到没有父类,从顶层父类开始数据属性对应的数据值,从上往下递归输出数据值。

你可能感兴趣的:(java,.net,oop)