您的位置:首页 > 编程语言 > Java开发

关于Java序列化的一些高级用法

2013-06-15 22:40 543 查看
该说的都在注释中说完了。直接给程序吧。

package test.javaPuzzler.p5;

import java.io.*;
import java.io.ObjectInputStream.GetField;
import java.io.ObjectOutputStream.PutField;

// 转载请注明来自http://blog.csdn.net/sunxing007
// 一个类实现Serializable来表明自己可以被序列化;
// 有一点需要特别注意的是:
// 如果子类实现了Serializable,而父类没有,则父类不会被序列化;
public class SerializableObject implements Serializable {

// 生成的序列化版本号会因为编译环境,声明的类名,成员名称和数量的变化而不同;
// 也就是说这个版本号一定程度上记录着类的定义性的信息,如果类的定义变化了,最好重新生成版本号;
// 如果新的代码使用了旧的版本号,则在反序列化的时候,可以兼容读取旧类的字节码而不会报错;
private static final long serialVersionUID = 9038542591452547920L;

public String name;
public String password;
// 如果你不希望某个非静态成员被序列化,可以用transient来修饰它;
public transient int age;
// 静态成员不会被序列化,因为序列化保存的是实例的状态信息,而静态成员是类的状态信息;
public static int version = 1;

public SerializableObject(String name, String password) {
this.name = name;
this.password = password;
}

// 每个类可以写一个writeObject方法,这个方法将会负责该类自身的序列化过程;
// 比如对于敏感信息如password,可以加密之后再序列化;
// 这个过程需要用到PutField,它可以指定哪些域会被序列化,怎么序列化(比如加密);
// 如果没有定义这个方法,将会调用ObjectOutputStream 的 defaultWriteObject;

// 你可以注释掉readObject方法,然后运行测试用例来测试密码是否被加密;
private void writeObject(ObjectOutputStream out) throws IOException {
PutField putFields = out.putFields();
putFields.put("name", name);
// 模拟加密密码
putFields.put("password", "thePassword:" + password);
out.writeFields();
}

// 每个类可以写一个readObject方法,该方法负责该类自身的反序列化过程;
// 比如对序列化时加密后的密码解密;
// 这个过程需要用到GetField,他可以具体地读取每个域;或执行解密动作等等;
// 如果没有定义这个方法,将会调用ObjectInputStream 的 defaultReadObject;
private void readObject(ObjectInputStream in)
throws ClassNotFoundException, IOException {
GetField readFields = in.readFields();
// 读取到成员的值之后,直接赋给该域,即完成该域的反序列化;
name = (String) readFields.get("name", "defaultName");
// 模拟解密密码
String encPassword = (String) readFields.get("password",
"thePassword:defaultValue");
password = encPassword.split(":")[1];
}

// 序列化
// 主要用到ObjectOutputStream;
public void save() throws IOException {
FileOutputStream fout = new FileOutputStream("e:\\obj");
ObjectOutputStream oout = new ObjectOutputStream(fout);
oout.writeObject(this);
oout.close();
fout.close();
}

// 反序列化
// 主要用到ObjectInputStream
public static SerializableObject load() throws IOException,
ClassNotFoundException {
FileInputStream fin = new FileInputStream("e:\\obj");
ObjectInputStream oin = new ObjectInputStream(fin);
Object o = oin.readObject();
return (SerializableObject) o;

}

@Override
public String toString() {
return "name: " + name + ", password: " + password;
}

// 测试用例
public static void main(String[] args) throws IOException,
ClassNotFoundException {
SerializableObject so = new SerializableObject(
"http://blog.csdn.net/sunxing007", "123456");
so.save();
System.out.println(so);
System.out.println(SerializableObject.load());
}

}

序列化会对单例模式不利, 因为可以通过反序列化而破坏单例. 这个时候就要请出readResolve这个方法了. 比如下面的程序:

public class Dog extends Exception {
//private static final long serialVersionUID = -7156412195888553079L;
public static final Dog INSTANCE = new Dog();
private Dog() { }
public String toString() {
return "Woof";
}
// 通过readResolve, 保证反序列化的时候能完全自主地处理返回对象.
private Object readResolve(){
return INSTANCE;
}
public static void main(String[] args) throws IOException, ClassNotFoundException{
Dog d = Dog.INSTANCE;
ByteArrayOutputStream bro = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(bro);
oout.writeObject(d);
ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(bro.toByteArray()));
Dog d1 = (Dog)oin.readObject();
System.out.println(d1==d);
}
}


[转载请注明来自http://blog.csdn.net/sunxing007]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: