今天学习的内容是ObjectOutputStream类和ObjectInputStream类
ObjectOutputStream类和ObjectInputStream类都是装饰器类,它们让字节流具备写入和读取二进制对象的功能。其中写入对象也称为对象的序列化--使用ObjectOutputStream类的writeObject()方法;而读取对象称为对象的反序列化--使用ObjectInputStream类的readObject()方法。对象序列化与反序列化的知识点总结如下:
- 只有实现Serializable接口的类的对象才能被序列化
- 可序列化类的子类是自动可序列化的
- 对象网的所有对象都会被序列化(比如对象中引用变量所指向的对象)
- 被序列化的变量只有非瞬时变量和非静态变量
- 瞬时变量由transient关键字修饰,瞬时变量不会被序列化,对象反序列化时该变量会被赋默认值
- 静态变量也不会被序列化,而且值不会被改变(因为静态变量存储在方法区中,即使是网络传输,也会在类第一次加载时存储在方法区)
- 读取对象的顺序与写入对象的顺序一致(读取的对象需要进行强制类型转换)
- 进行对象反序列化时,要通过serialVersionUID验证类和对象是否为同一版本(强烈建议显式声明serialVersionUID,但是对类的修改不能对对象的反序列化造成影响)
- 对象反序列化不会调用构造函数(这种对象就是传说中不是被new出来的对象!!)
程序示例:
public class Test91 {
public static void main(String[] args) throws ClassNotFoundException {
// 对象序列化
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("obj.ser"));
oos.writeObject(new Person("k", 11));// 如果参数类型没有实现Serializable接口,发生NotSerializableException
oos.writeObject(new Person("kk", 21));
oos.writeObject(new Person("kkk", 31));
// oos.writeObject(new Student());可序列化的类的子类是自动可序列化的
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
throw new RuntimeException("关闭资源失败");
}
}
}
// 对象的反序列化
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("obj.ser"));
Person p1 = (Person) ois.readObject();
Person p2 = (Person) ois.readObject();
Person p3 = (Person) ois.readObject();
ArrayList<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
for (Person person : list) {// 读取对象的顺序与写入对象的顺序一致
System.out.println("非静态变量:" + person.getName());// 非静态变量的值被还原
System.out.println("瞬时变量:" + person.getAge());// 瞬时变量会被赋默认值0
System.out.println("静态变量:" + Person.getLength());// 静态变量的值不变
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
throw new RuntimeException("关闭资源失败");
}
}
}
}
}
class Person implements Serializable {// 如果要让该类对象可以被序列化,就实现Serializable接口
/**
*
*/
private static final long serialVersionUID = 393843429975524886L;
private String name;
private transient int age;// 反序列化之后会被赋默认值0
private static int length = 100;
public Person() {
super();
}
public Person(String name, int age) {
super();
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;
}
public static int getLength() {
return length;
}
public static void setLength(int length) {
Person.length = length;
}
}
class Student extends Person {
/**
*
*/
private static final long serialVersionUID = -8780508815255118201L;
}