1. 普通序列化 implements Serializable
继承Serializable接口
class Employee implements Serializable {
private String name;
private double salary;
private LocalDate hireDay;
public Employee() {
}
public Employee(String n, double s, int year, int month, int day) {
name = n;
salary = s;
hireDay = LocalDate.of(year, month, day);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public LocalDate getHireDay() {
return hireDay;
}
public void setHireDay(LocalDate hireDay) {
this.hireDay = hireDay;
}
public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
public String toString() {
return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";
}
}
// 1. 普通序列化
Employee employee = new Employee("Harry Hacker", 50000, 1989, 10, 1);
try (FileOutputStream personOutputStream = new FileOutputStream("E:\employee.dat");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(personOutputStream);) {
objectOutputStream.writeObject(employee);
}
try (FileInputStream personInputStream = new FileInputStream("E:\employee.dat");
ObjectInputStream objectInputStream = new ObjectInputStream(personInputStream);) {
Object readObject = objectInputStream.readObject();
if (readObject instanceof Employee) {
Employee tempEmployee = (Employee) readObject;
System.out.println(tempEmployee.toString());
}
}
System.out.println();
执行结果io.Employee[name=Harry Hacker,salary=50000.0,hireDay=1989-10-01]
2. 关联对象
一个employee被多个Manager关联, 反序列后还是同一个。
// 2. 关联对象 一个employee被多个Manager关联, 反序列后还是同一个
Manager manager1 = new Manager("Carl Cracker", 80000, 1987, 12, 15);
manager1.setSecretary(employee);
Manager manager2 = new Manager("Tony Tester", 40000, 1990, 3, 15);
manager2.setSecretary(employee);
try (FileOutputStream managerOutputStream = new FileOutputStream("E:\manager.dat");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(managerOutputStream);) {
objectOutputStream.writeObject(manager1);
objectOutputStream.writeObject(manager2);
}
try (FileInputStream managerInputStream = new FileInputStream("E:\manager.dat");
ObjectInputStream objectInputStream = new ObjectInputStream(managerInputStream);) {
Object readObject1 = objectInputStream.readObject();
Object readObject2 = objectInputStream.readObject();
if (readObject1 instanceof Manager) {
Manager tempManager = (Manager) readObject1;
System.out.println(tempManager.toString());
System.out.println(tempManager.getSecretary().hashCode());
}
if (readObject2 instanceof Manager) {
Manager tempManager = (Manager) readObject2;
System.out.println(tempManager.toString());
System.out.println(tempManager.getSecretary().hashCode());
}
}
System.out.println();
执行结果
io.Manager[name=Carl Cracker,salary=80000.0,hireDay=1987-12-15][secretary=io.Employee[name=Harry Hacker,salary=50000.0,hireDay=1989-10-01]]
381259350
io.Manager[name=Tony Tester,salary=40000.0,hireDay=1990-03-15][secretary=io.Employee[name=Harry Hacker,salary=50000.0,hireDay=1989-10-01]]
381259350
3. 忽略冗余字段 transient
不能使用javax.persistence.Trasient,使用关键字 transient
class Employee implements Serializable {
private String name;
private transient double salary;
private LocalDate hireDay;
...
}
执行1的结果io.Employee[name=Harry Hacker,salary=0.0,hireDay=1989-10-01]
4. 保护性恢复 readResolve()&writeReplace()
writeReplace() 在序列化时会先调用writeReplace方法将当前对象替换成另一个对象(该方法会返回替换后的对象)并将其写入流中;
readResolve() 在readObject调用之后自动调用,它最主要的目的就是让恢复的对象变个样.
对于单例对象, 序列化后取得的对象要与序列化之前的对象一致才行; 可以使用readResolve()在read时做一些处理.
class MySingleton implements Serializable {
private MySingleton() {
}
private static final MySingleton INSTANCE = new MySingleton();
public static MySingleton getInstance() {
return INSTANCE;
}
private Object writeReplace() throws ObjectStreamException{
return INSTANCE;
}
private Object readResolve() throws ObjectStreamException {
return INSTANCE;
}
}
下面代码返回trueMySingleton mySingleton = MySingleton.getInstance();
try (FileOutputStream mySingletonOutputStream = new FileOutputStream("E:\mySingleton.dat");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(mySingletonOutputStream);) {
objectOutputStream.writeObject(mySingleton);
}
try (FileInputStream mySingletonInputStream = new FileInputStream("E:\mySingleton.dat");
ObjectInputStream objectInputStream = new ObjectInputStream(mySingletonInputStream);) {
Object readObject = objectInputStream.readObject();
if (readObject instanceof MySingleton) {
MySingleton orientation = (MySingleton) readObject;
// (1) 没有readResolve()方法时; 序列化new出的是新对象,和原先对象不相等
// (2) 添加readResolve()方法后, 序列化之后调用readObject()时会调用readResolve()方法
System.out.println(mySingleton == orientation);
}
}
System.out.println();
5. readObjectNoData()
数据结构改变后, 调用readObjectNoData()方法.
初始化Person, 指定掌纹
class Person implements Serializable {
private static final long serialVersionUID = 8427041451926540477L;
public Person() { }
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
将其序列化Person p = new Person();
p.setAge(10);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/person.dat"));
oos.writeObject(p);
oos.flush();
oos.close();
类结构变化后class Animal implements Serializable {
private String name;
public Animal() { }
private void readObjectNoData() {
this.name = "zhangsan";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Person extends Animal {
private static final long serialVersionUID = 8427041451926540477L;
public Person() { }
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
执行ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/person.dat"));
Person sp = (Person) ois.readObject();
System.out.println(sp.getName());
ois.close();
得到 zhangsan6. Externalizable接口
由开发者完全决定如何序列化和反序列化目标对象
注意: 必须提供一个无参构造器,访问权限为public; 否则会抛出java.io.InvalidClassException 异常
class Student implements Externalizable {
private String name;
private int age;
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeInt(age);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = (String)in.readObject();
age = in.readInt();
}
//no valid constructor
//必须提供一个无参构造器,访问权限为public;否则会抛出java.io.InvalidClassException 异常
public Student() {
// TODO Auto-generated constructor stub
}
public Student(String name, int age) {
this.name= name;
this.age=age;
}
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 String toString() {
return "name:"+name+", age: "+age;
}
}
序列化Student student = new Student("name", 20);
try (FileOutputStream studentOutputStream = new FileOutputStream("E:\student.dat");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(studentOutputStream);) {
objectOutputStream.writeObject(student);
}
try (FileInputStream studentInputStream = new FileInputStream("E:\student.dat");
ObjectInputStream objectInputStream = new ObjectInputStream(studentInputStream);) {
Object readObject = objectInputStream.readObject();
if (readObject instanceof Student) {
System.out.println(((Student) readObject).toString());
}
}
System.out.println();
结果: name:name, age: 207. 为克隆使用序列化
实现深拷贝
class SerialCloneable implements Cloneable, Serializable {
public Object clone() throws CloneNotSupportedException {
try {
// save the object to a byte array
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(bout)) {
out.writeObject(this);
}
// read a clone of the object from the byte array
try (InputStream bin = new ByteArrayInputStream(bout.toByteArray())) {
ObjectInputStream in = new ObjectInputStream(bin);
return in.readObject();
}
} catch (IOException | ClassNotFoundException e) {
CloneNotSupportedException e2 = new CloneNotSupportedException();
e2.initCause(e);
throw e2;
}
}
}
class Employee extends SerialCloneable {
private String name;
private double salary;
private LocalDate hireDay;
...
}
执行//7. 深拷贝
Employee harry = new Employee("Harry Hacker", 35000, 1989, 10, 1);
// clone harry
Employee harry2 = (Employee) harry.clone();
// mutate harry
harry.raiseSalary(10);
// now harry and the clone are different
System.out.println(harry);
System.out.println(harry2);
结果
io.Employee[name=Harry Hacker,salary=38500.0,hireDay=1989-10-01]
io.Employee[name=Harry Hacker,salary=35000.0,hireDay=1989-10-01]