java流(二)
目录
1 ObjectOutputStream/ObjectInputStream的使用
2 序列化
3 具体序列化的过程
4 Externalizable的简易介绍
实现序列化的Person类
/** * 测试序列化所用的类 */ class Person implements Serializable { private String username; private transient String password; //反序列化 public Person(String username,String password) { this.username = username; this.password = password; } public String toString() { StringBuffer str = new StringBuffer(); str.append("username=" + this.username+"\r\n"); str.append("password=" + this.password); return str.toString(); } }
注意 password字段使用了transient表示,该字段不实现序列化(即,读取这个类时这个字段的值恒定位null)
测试方法
public class SerializableTest2 { public static void main(String args[]) throws IOException, ClassNotFoundException { testObjectSeri(); testObjectInSeri(); } public static void testObjectSeri() throws IOException { Person person = new Person("测试", "java"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat")); oos.writeObject("字符串"); oos.writeObject(person); oos.flush(); oos.close(); System.out.println("入参:"+"\r\n"+"字符串 "+"\r\n"+person.toString()); } public static void testObjectInSeri() throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat")); String str = (String) ois.readObject(); System.out.println(str); Person person = (Person) ois.readObject(); ois.close(); System.out.println(person.toString()); } }
执行结果
入参: 字符串 username=测试 password=java 字符串 username=测试 password=null
注意读取数据时要按照传入顺序转换成对应的对象类型。
我们再来详细的看一下,序列化的过程
改造一下Person类
class Person implements Serializable { private String username; private transient String password; //反序列化 public Person(String username,String password) { this.username = username; this.password = password; } public String toString() { StringBuffer str = new StringBuffer(); str.append("username=" + this.username+"\r\n"); str.append("password=" + this.password); return str.toString(); } private void writeObject(java.io.ObjectOutputStream out) throws IOException { System.out.println("writeObject invoked"); } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { System.out.println("readObject invoked"); } private Object writeReplace() throws ObjectStreamException { System.out.println("writeReplace invoked"); return this; } private Object readResolve() throws ObjectStreamException { System.out.println("readResolve invoked"); return this; } }
继续使用上面的测试方法
执行结果
writeReplace invoked writeObject invoked 入参: 字符串 username=测试 password=java 字符串 readObject invoked readResolve invoked username=null password=null
序列化与反序列化的内部执行按照以下顺序
writeReplace --> writeObject
readObject --> readResolve
结论
当进行序列化的时候:
首先JVM会先调用writeReplace方法,在这个阶段,我们可以进行张冠李戴,将需要进行序列化的对象换成我们指定的对象. (入口)
跟着JVM将调用writeObject方法,来将对象中的属性一个个进行序列化,我们可以在这个方法中控制住哪些属性需要序列化.
当反序列化的时候:
JVM会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性,反序列化回来.
然后在readResolve方法中,我们也可以指定JVM返回我们特定的对象(不是刚刚序列化回来的对象).
另外 Externalizable 和是一个有实际方法需要实现的interface,包括writeExternal和readExternal:
现在在person后面添加这2个方法
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { System.out.println("readExternal"); } public void writeExternal(ObjectOutput out) throws IOException { System.out.println("writeExternal"); }
执行结果
writeReplace invoked writeExternal//-----覆盖之前的方法被执行 入参: 字符串 username=测试 password=java readExternal//-----覆盖之前的方法被执行 readResolve invoked username=null password=null
参考文章
http://www.cnblogs.com/xt0810/p/3642904.html
http://dovecat.iteye.com/blog/66044
http://blog.csdn.net/yakihappy/article/details/3979373
http://developer.51cto.com/art/200908/147650.htm
http://dusiguxia.blog.163.com/blog/static/55629316201162635435180/