Java 序列化有两种方式.
1. 实现Serializable 接口
// 1: implements serializable
public class Person implements Serializable {
int age;
String name;
transient String hobby = "string";
public Person(int age, String name) {
this.age = age;
this.name = name;
this.hobby = "hobby";
}
@Override
public String toString() {
return String.format("age: %d name %s %s", age, name, hobby);
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
String fileName = "o.out";
Person p = new Person(22, "hello");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName));
out.writeObject(p);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
Person p2 = (Person) in.readObject();
System.out.println(p2);
}
}
如果要让Serializable 像 Externalizable 一样实现操作transient属性,可以添加 readObject 和 writeObject 方法,如下:
import java.io.*;
// 1: implements serializable
public class Person implements Serializable {
int age;
String name;
transient String hobby ;
public Person(int age, String name) {
this.age = age;
this.name = name;
this.hobby = "ping pong";
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
hobby = (String) in.readObject();
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeObject(hobby);
}
@Override
public String toString() {
return String.format("age: %d name %s %s", age, name, hobby);
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
String fileName = "o.out";
Person p = new Person(22, "hello");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName));
out.writeObject(p);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
Person p2 = (Person) in.readObject();
System.out.println(p2);
}
}
2. 实现 Externalizable 接口
注意点:
a> 实现Externalizable 的类的构造函数必须是public的
import java.io.*;
class Blip1 implements Externalizable{
public Blip1(){
}
public void writeExternal(ObjectOutput out) throws IOException {
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
}
}
class Blip2 implements Externalizable{
// pay attention: the constructor must be public
public Blip2(){
}
public void writeExternal(ObjectOutput out) throws IOException {
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
}
}
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Blip1 b1 = new Blip1();
Blip2 b2 = new Blip2();
final String fileName = "blips.out";
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName));
out.writeObject(b1);
out.writeObject(b2);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
b1 = (Blip1) in.readObject();
b2 = (Blip2) in.readObject();
}
}
总结,两者的区别:
1. Serializable 在 readObject 的时候不需要调用类的默认构造函数,以此如果有transitent 属性,就会是null,数字就是0.
2. Externalizable 在readObject 的时候必须要调用类的构造函数,以此要求类的默认的构造函数必须要是public的.
3. 如果不想讲一个类里面的属性序列化,在Serializable 里面可以加上 transient 关键字修饰这个属性,而在Externalizable 里面可以在 writeExternal 和 readExternal 方法中不操作这个属性, 不能在Externalizable 中使用transient 关键字.
4. 如果是将序列化对象写入到同一个文件中,那么对象间的引用关系还是存在的,如果是不同的文件中,那么对象间的引用关系就丢失了.(参考 https://www.ibm.com/developerworks/cn/java/j-lo-serial/index.html )
5. java 无法序列化 类中的静态属性,如果只能自己写一些方法来解决这个问题.