一个对象只要实现了Serializable接口,该对象就可以被序列化。然而在实际开发过程中,常常会遇到这样的问题,该类有些属性需要序列化,其他属性不需要被序列化。例如一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及序列化)中被传输,这些信息对应的变量就可以加上transient关键字,这样变量的生命周期仅存在于调用者的内存中而不会被写到磁盘里持久化。
序列化与反序列化
持久化对象、RMI(远程方法调用)、在网络中传递对象时,会用到对象序列化。在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其他对象也进行序列化。
序列化:把对象转换为字节序列的过程
反序列化:把字节序列恢复为对象的过程
java中只要实现了Serializable、Externalizable接口的类的对象就可被序列化。
实现Java对象序列化与反序列化的方法
方法一:若类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化
ObjectOutputStream采用默认的序列化方式,将对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,将对象的非transient的实例变量进行反序列化。
方法二:若类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
ObjectOutputStream调用对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用对象的readObject(ObjectInputStream in)的方法进行反序列化。
方法三:若类实现了Externalnalizable接口,且类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
ObjectOutputStream调用对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用对象的readExternal(ObjectInput in)的方法进行反序列化。
对象序列化和反序列化实例(方法一)+transient关键字:
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable;
/** * @Title: SerializableTest.java * @author olive * @date Feb 19, 2016 9:28:30 AM * 序列化: 把对象转换为字节序列的过程 * 反序列化: 把字节序列恢复为对象的过程 */ public class SerializableTest implements Serializable{ /** * serializable ID */ private static final long serialVersionUID = -7873944822450384597L; private String username; private transient String psw; public SerializableTest(String username,String psw){ this.username=username; this.psw=psw; }
/** * @return the username */ public String getUsername() { return username; }
/** * @param username the username to set */ public void setUsername(String username) { this.username = username; }
/** * @return the psw */ public String getPsw() { return psw; }
/** * @param psw the psw to set */ public void setPsw(String psw) { this.psw = psw; } public static void main(String[]args){ SerializableTest a=new SerializableTest("mary","12345"); String file="D:\\tmp.txt"; try { System.out.println("username:"+a.getUsername()+" password:"+a.getPsw()); // 使用ObjectOutputStream将对象SerializableTest序列化,并将其保存到文件中 FileOutputStream fos=new FileOutputStream(file); ObjectOutputStream out=new ObjectOutputStream(fos); out.writeObject(a); out.flush(); out.close(); fos.close(); // 使用ObjectInputStream将对象反序列化 ObjectInputStream in=new ObjectInputStream(new FileInputStream("D:\\tmp.txt")); SerializableTest test=(SerializableTest)in.readObject(); System.out.println("username:"+test.getUsername()+" password:"+test.getPsw()); in.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
输出:
|
密码为null,说明反序列化没有从文件中得到该信息。
Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
参考:
http://www.cnblogs.com/lanxuezaipiao/p/3369962.html
http://blog.csdn.net/wangloveall/article/details/7992448
http://www.cnblogs.com/xdp-gacl/p/3777987.html
http://developer.51cto.com/art/201202/317181.htm
http://www.cnblogs.com/guanghuiqq/archive/2012/07/18/2597036.html