序列化与反序列化
序列化就是将对象的状态信息转换为可以存的字节序列存等储,在以后将这个字节序列恢复成对象就是反序列化。
实现Serializable的方式
public class Fruit implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private int size;
/**
* @param name
* @param size
*/
public Fruit(String name, int size) {
super();
this.name = name;
this.size = size;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
@Override
public String toString() {
return "Fruit [name=" + name + ", size=" + size + "]";
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
Fruit fruit = new Fruit("banana", 100);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream stream = new ObjectOutputStream(out);
stream.writeObject(fruit);
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
Fruit fruitRecover = (Fruit) in.readObject();
System.out.println(fruitRecover);
}
输出:
Fruit [name=banana, size=100]
上面的例子中可以自定义读和写方法,如果有则调用自己的方法在Fruit中加入
private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
in.defaultReadObject();
//可以用自己的逻辑读数据
System.out.println("readObject");
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
//可以用自己的逻辑写数据
System.out.println("writeObject");
}
注意点
- 尽量在需要序列化的类中定义序列serialVersionUID ,否则虚拟机将自动调用方法实现一个序列,影响性能。
- transient关键字的字段无法实现序列。
- 静态成员属于类级别的,所以不能序列化,除非你都在同一个机器(而且是同一个进程),且jvm已经把字段加载进来了。
实现Externalizable的方式
这种方法必须要自己实现读和写,并且必须要有无参数构造器,看下代码
public class Person implements Externalizable {
private String name;
private int age;
public Person() {
super();
System.out.println("default constructor");
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
System.out.println("params constructor");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeInt(age);
System.out.println("writeExternal");
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
name = (String) in.readObject();
age = in.readInt();
System.out.println("readExternal");
}
}
public static void testES() throws IOException, ClassNotFoundException {
Person person = new Person("zzh", 20);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream stream = new ObjectOutputStream(out);
stream.writeObject(person);
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
Person p = (Person) in.readObject();
System.out.println(p.getAge());
}
输出:
params constructor
writeExternal
default constructor
readExternal
20
一些使用场景
- 在一些网络传输、RMI等远程传输。
- tomcat在重启时,也会将session中的对象序列化,我们不需要重新登录。
- 使用jrdis保存对象时也能用到。