Java 中如何序列化一个对象
我们都知道java 中无法保存一个对象到文本文件中,但是当我们有这种需求的时候,我们可以通过java 的序列化功能把当前对象的一些属性以二进制的形式保存到文件中。当我们需要这个对象的时,只需要从二进制文件中还原为保存前的对象即可。从这里我们可以得到启发,如果想把机器A 上的一个Student 对象发送到机器B 上,我们可以把Student 对象序列化成二进制,然后把该二进制发送给机器B ,机器B 就可以根据二进制数据还原成Student 对象了,这就变相的实现了在机器间传播对象的功能。
写入序列化数据到文件中,主要是两个对象,一个对象是FileOutputStream 对象,一个是ObjectOutputStream 对象,ObjectOutputStream 负责向指定的流中写入序列化的对象。当从文件中读取序列化数据时,主要需要两个对象,一个是FileInputStream ,一个是ObjectInputStream 对象,ObjectInputStream 负责从指定流中读取序列化数据并还原成序列化前得对象。另外,序列化的读取数据与写入的顺序相同,比如我们序列化时先写入数据A ,再写入B ,最后写入C ;那么我们再读取数据的时候,读取到的第一个数据为A ,读取到的第二个数据为B ,最后读取到的数据为C ,即:先写入先读取的原则。
在序列化一个对象的时候,这个对象必须实现java.io.Serializable 接口, Serializable 接口中不含任何方法,这个可以理解为声明该对象是可以序列化的方法吧。当我们在序列化一个对象时,有些属性我们不想序列化(可以减少数据量),那么我们可以声明该属性为瞬间态(用transient 关键字声明)。另外,静态字段也是不会被序列化的。
当我们在序列化一个对象时,如果该对象没有覆写writeObject 或者readObject 方法,那么系统将采用默认的方法进行序列化,如果序列化对象中有这两个方法,则采用对象中的这两个方法进行序列化。至于如何找到的这两个方法,通过代码我们可以跟踪到是根据反射的方式进行判断对象是否覆写这两个方法。另外,这两个方法在对象中是
一、 序列化一个List 对象
[1] Java 代码
package com.csdn.serialize;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List;
public class TestAnotherSerialize {
/** * @param args * @throws IOException * @throws ClassNotFoundException */ public static void main(String[] args) throws IOException, ClassNotFoundException {
// 1. 准备数据 List dataList = new ArrayList(); dataList.add("abc"); dataList.add("123");
// 2. 构造序列化流 String sFilePath = "D://test_another_serialize.dat"; FileOutputStream fos = null; ObjectOutputStream ooS = null; try { fos = new FileOutputStream(sFilePath); ooS = new ObjectOutputStream(fos); ooS.writeObject(dataList); } catch (Exception ex) { ex.printStackTrace(); } finally { if (fos != null) fos.close(); if (ooS != null) { ooS.close(); } }
// 3. 从序列化文件中读取出文件 FileInputStream fiStream = null; ObjectInputStream oiStream = null; try { fiStream = new FileInputStream(sFilePath); oiStream = new ObjectInputStream(fiStream);
List serializeResult = (List) oiStream.readObject(); System.out.println(" 序列化结果为::" + serializeResult);
} catch (Exception ex) { ex.printStackTrace(); } finally { if (fiStream != null) fiStream.close(); if (oiStream != null) { oiStream.close(); } } } } |
[2] 输出结果
运行上边的代码,可以看到执行结果如下,即:从文件中可以还原出写入的序列化对象。
序列化结果为:: [abc, 123] |
二、 序列化一个对象
这里利用TestSerialize 类来测试序列化对象SerializeStudent ,SerializeStudent 里Class 属性是瞬时态的,Dept 属性是static ,StudentName 是非瞬时态也非static 。
[1] 序列化对象SerializeStudent 代码
package com.csdn.serialize;
import java.io.Serializable;
public class SerializeStudent implements Serializable {
/** * 序列化对象的标识,用于在反序列化的时候使用 <BR> * 反序列化的时候,如果当前内存中已经有这个标识的对象,则认为是同一类对象 */ private static final long serialVersionUID = -6193310436318894856L;
/* 演示瞬时态对象不会被序列化 */ private transient String m_nClass = null ;
/* 成员属性 */ private String m_sStudentName = null ;
public static String m_sDept = null ;
public void setStudentName(String studentName) { m_sStudentName = studentName; }
public void setDept(String _sDept) { m_sDept = _sDept; }
public void setClass(String _nAge) { m_nClass = _nAge; }
@Override public String toString() { return " 学生姓名: " + m_sStudentName + ", 系 ( 静态字段 ) : " + m_sDept + ", 班级 ( 瞬时态字段 ) : " + m_nClass ; } }
|
[2] 测试类TestSerialize 代码
package com.csdn.serialize;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream;
public class TestSerialize {
/** * @param args * @throws IOException * @throws ClassNotFoundException */ public static void main(String[] args) throws IOException, ClassNotFoundException {
// 1. 序列化文件保存的地址 String sFilePath = "D://test_serialize.oo" ;
// 2. 序列化对象到文件中 testWriteObject (sFilePath);
// 读取字段 testReadObject (sFilePath); }
/** * 序列化一个 aStudent 对象到文件中 * * @throws IOException */ private static void testWriteObject(String _sFilePath) throws IOException { // 1. 构造 SerializeStudent 对象 SerializeStudent aStudent = new SerializeStudent(); aStudent.setStudentName( "wuguowei" ); // 非瞬时态又是非静态字段,所以肯定会序列化 aStudent.setDept( "computer " ); // dept 是 static ,这里不会被序列化,如果被序列化的话,那么值应该为 computer aStudent.setClass( "04133" ); // 由于 class 是 transient ,所以不会被序列化
// 2. 构造序列化流 FileOutputStream fos = null ; ObjectOutputStream ooS = null ; try { fos = new FileOutputStream(_sFilePath); ooS = new ObjectOutputStream(fos); ooS.writeObject(aStudent); } catch (Exception ex) { ex.printStackTrace(); } finally { if (fos != null ) fos.close(); if (ooS != null ) { ooS.close(); } }
// 3. 还原静态字段,以免影响测试 aStudent.setDept( null ); }
/** * 从序列化文件中读取出 serializeStudent 对象 * * @throws IOException */ private static void testReadObject(String _sFilePath) throws IOException {
// 1. 从序列化文件中读取出文件 FileInputStream fiStream = null ; ObjectInputStream oiStream = null ; try { fiStream = new FileInputStream(_sFilePath); oiStream = new ObjectInputStream(fiStream);
// 读取信息 SerializeStudent readStudent = (SerializeStudent) oiStream .readObject(); System. out .println( " 当前学生信息 ::" + readStudent); } catch (Exception ex) { ex.printStackTrace(); } finally { if (fiStream != null ) fiStream.close(); if (oiStream != null ) { oiStream.close(); } } } } |
[3] 执行TestSerialize 类的输出结果
输出结果如下,从下面结果可以看出Class 和Dept 属性没有被序列化(因为还原后的对象为null ),但是StudentName 被序列化了。
当前学生信息:: 学生姓名:wuguowei , 系( 静态字段) :null , 班级( 瞬时态字段) :null |