简介
- 序列化:将对象写入到IO流中
- 反序列化:从IO流中恢复对象
- 意义:序列化机制允许将实现序列化的Java对象转换为字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。
- 使用场景:所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:程序创建的每个JavaBean类都实现Serializeable接口。
实现方式
序列化
- 创建一个ObjectOutputStream输出流
- 调用ObjectOutputStream对象的writeObject输出可序列化对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.io.*;
public class Person implements Serializable { private String name; private int age;
public Person(String name, int age) { this.age = age; this.name = name; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } } class WriteObject { public static void main(String args[]) { try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\test.txt")); Person person = new Person("wawyw", 18); oos.writeObject(person); System.out.println("序列化成功"); } catch (Exception e) { e.printStackTrace(); } } }
|
反序列化
- 创建一个ObjectInputStream输入流
- 调用ObjectInputStream对象的readObject()得到序列化的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.io.*;
public class Person implements Serializable { private String name; private int age;
public Person(String name, int age) { this.age = age; this.name = name; System.out.println("反序列化调用我这个构造方法了嘛?"); }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } } class ReadObject { public static void main(String args[]) { try { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\test.txt")); Person wawyw = (Person) ois.readObject(); System.out.println(wawyw); }catch (Exception e){ e.printStackTrace(); } } }
|
输出告诉我们,反序列化并不会调用构造方法。反序列的对象是由JVM自己生成的对象,不通过构造方法生成。
transient
使用transient关键字选择不需要序列化的字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import java.io.*;
public class Person implements Serializable { private transient String name; private transient int age; private int height; private transient boolean singlehood; public Person(String name, int age){ this.name = name; this.age = age; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", height=" + height + ", singlehood=" + singlehood + '}'; } } class TransientTest{ public static void main(String[] args){ try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\a.txt")); Person person = new Person("wawyw",18); oos.writeObject(person); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\a.txt")); Person wawyw = (Person) ois.readObject(); System.out.println(wawyw); }catch (Exception e){ e.printStackTrace(); } } }
|
使用transient修饰的属性,java序列化时,会忽略掉此字段,所以反序列化出的对象,被transient修饰的属性是默认值。对于引用类型,值是null;基本类型,值是0;boolean类型,值是false。
自定义序列化
java提供了可选的自定义序列化。可以进行控制序列化的方式,或者对序列化数据进行编码加密等。
通过重写writeObject与readObject方法,可以自己选择哪些属性需要序列化, 哪些属性不需要。如果writeObject使用某种规则序列化,则相应的readObject需要相反的规则反序列化,以便能正确反序列化出对象。这里展示对名字进行反转加密。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import java.io.*;
public class Person implements Serializable { private String name; private int age;
private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(new StringBuffer(this.name).reverse()); out.writeInt(age); }
private void readObject(ObjectInputStream ins) throws IOException,ClassNotFoundException{ this.name = ((StringBuffer)ins.readObject()).reverse().toString(); this.age = ins.readInt(); } }
|