Java 序列化高级篇
我们只知道类实现Serializable 或者Externalizable就能实现序列化,存储在本地。但是多了解一些总是有好处。
一、序列化ID
序列化ID=属性名+时间戳,反序列化的前提是序列化ID得相同。Eclipse提供两种产生序列化ID的方法,一种是:属性名+时间戳,另一种是我们一般用1L表示。
设计模式中有Faced模式。
- S:服务器
- C:客户端
- D:通过D对象才能访问a和b
- a:a类业务逻辑
- b:b类业务逻辑
客户端的D对象是服务端序列化穿过来,在客户端反序列化得到的。如果服务端对D进行更新,更新后把序列ID更改,更改后客户端的序列ID与服务端序列ID不同,所以反序列化失败,则需要服务端再序列化D传到客户端。依此完成更新。
二、序列化中的静态变量
结论:序列化存储的是对象的状态,类的状态不存储。
public class MainTest implements Externalizable {
private static String userName = "张三";
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// TODO Auto-generated method stub
out.writeUTF(userName);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
System.out.println(in.readUTF());
}
public static void main(String[] args) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:\\java.txt")));
oos.writeObject(new MainTest());
MainTest.userName = "李四";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:\\java.txt")));
MainTest obj = (MainTest) ois.readObject();
oos.close();
ois.close();
System.out.println(obj.userName);
}
}
结果是
李四
三、加密解密
比如准备给password序列化时将她加密后序列化,反序列化后解密对照密匙将它解密。
四、子类序列化时父类的情况
父类没实现Serializable接口那么,子类序列化时父类不会序列化。当反序列化变为对象时,因为子类对象创建会先创建父类,所以会调用父类的构造方法。子类对象的属性的值存在,父类对象的属性的值为0或者为null。
五、序列化存储两次同一对象
public class MainTest implements Externalizable {
private String userName;
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
}
public static void main(String[] args) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:\\java.txt")));
MainTest t = new MainTest();
oos.writeObject(t);
oos.flush();
System.out.println(new File("d:\\java.txt").length());
oos.writeObject(t);
System.out.println(new File("d:\\java.txt").length());
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:\\java.txt")));
MainTest obj = (MainTest) ois.readObject();
MainTest obj1 = (MainTest) ois.readObject();
oos.close();
ois.close();
System.out.println(obj == obj1);
}
}
结果
40
45
true
读取了两次都是同一对象。并且存储两次应该存储空间变为两倍,这里只增加了5,因为存储第二次时只存储对象的引用加控制信息。
六、存储两次相同对象,第二次存储改变属性值
public class MainTest implements Serializable {
String userName;
public static void main(String[] args) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:\\java.txt")));
MainTest t = new MainTest();
t.userName = "张三";
oos.writeObject(t);
oos.flush();
t.userName = "李四";
oos.writeObject(t);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:\\java.txt")));
MainTest obj = (MainTest) ois.readObject();
MainTest obj1 = (MainTest) ois.readObject();
oos.close();
ois.close();
System.out.println(obj.userName);
System.out.println(obj1.userName);
}
}
结果为
张三
张三
因为两个存储同一对象,只会存储第一次对象。第二次值存储对象的引用和控制信息。