ObjectOutputStream和ObjectInputStream的使用
ObjectOutputStream
ObjectOutputStream是一个高级流, 将 Java 对象的基本数据类型和图形写入 OutputStream。
继承的类
public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants
构造函数
public ObjectOutputStream(OutputStream out);
创建写入指定 OutputStream 的 ObjectOutputStream。此构造方法将序列化流部分写入底层流;调用者可以通过立即刷新流,确保在读取头部时,用于接收 ObjectInputStreams 构造方法不会阻塞。
protected ObjectOutputStream();
为完全重新实现 ObjectOutputStream 的子类提供一种方法,让它不必分配仅由 ObjectOutputStream 的实现使用的私有数据。
常用方法
public final void writeObject(Object obj);
指定的对象写入 ObjectOutputStream。对象的类、类的签名,以及类及其所有超类型的非瞬态和非静态字段的值都将被写入。
ObjectInputStream
ObjectInputStream也是一个高级流,对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
继承的类
public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants
构造函数
public ObjectInputStream(InputStream in);
创建从指定 InputStream 读取的 ObjectInputStream。从流读取序列化头部并予以验证。在对应的 ObjectOutputStream 写入并刷新头部之前,此构造方法将阻塞。
protected ObjectInputStream();
为完全重新实现 ObjectInputStream 的子类提供一种方式,让它不必分配仅由 ObjectInputStream 的实现使用的私有数据。
常用方法
public final Object readObject();
从 ObjectInputStream 读取对象。对象的类、类的签名和类及所有其超类型的非瞬态和非静态字段的值都将被读取。
实现序列化和反序列化
实现序列化的步骤:
1)创建一个ObjectOutputStream对象
2)写到磁盘上调用writeObject()
实现反序列化的步骤:
1)创建一个ObjectInputStream对象
2)从磁盘上读取当前的二进制流并将其转换为一个Person对象则调用readObject()
class Person implements Serializable{
private String name;
private int age;
public Person(String name, int age){
System.out.println("实例化对象");
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 class TestDemo8 {
public static void main(String[] args) {
//序列化Person对象
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
Person p = new Person("tulun", 18);
oos.writeObject(p);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//反序列出Person对象
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("a.txt"));
Person p = (Person)ois.readObject();
System.out.println(p.getName()+":: "+p.getAge());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
ArrayList序列化和反序列化
public static void arrayListSerial(){
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("tulun");
list.add("education");
//ObjectOutputStream oos = null;
try {
//序列化过程
//输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("stringList.txt"));
//调用流对象的writeObject将当前对象写入到磁盘的文件中
oos.writeObject(list);
oos.close();
//反序列化过程
//输入流对象
File file = new File("stringList.txt");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
//调用流对象的readObject读取当前对象的字节流
List<String> newList = (List<String>)ois.readObject();
System.out.println(newList);
ois.close();
if(file.exists()){
file.delete();
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
arrayListSerial();
}
其中ArrayList重写writeObject和readObject
原因:ArrayList底层基于一个动态数组实现,每次在数组满后都会自动进行扩容,如果当前数组的长度为100,此时只放入了一个元素,使用默认的writeObject和readObject就会使其序列化99个null元素,为了保证序列化的时候不会将无效元素进行序列化,首先将ArrayList底层存储元素的容器被transient关键字修饰,所以重写了writeObject和readObject去序列化ArrayList当中的有效元素
transient作用:
被transient关键字修饰的变量在序列化过程中不会被序列化的