1、基本介绍
1.对象的序列化:将Object类型的对象转换成byte序列,简单来讲就是要存储对象,将对象写入文件。
序列化流(ObjectOutputStream),核心方法writeObject()
2.对象的反序列化:将byte序列转换成Object类型的对象,简单来讲就是从文件中读取对象。
反序列化流(ObjectInputStream),核心方法readObject()
3.序列化接口:对象必须实现序列化接口(Serializable),才能进行序列化,否则将出现异常。该接口中没有任何方法,只是一个标准。
注意:
当一个类实现了序列化接口,其子类都可以实现序列化;
对子类对象实现反序列化操作时,如果其父类没有实现序列化接口,那么其父类的构造方法会被调用,不会进行反序列化。
2、实现对象的序列化——写入对象
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
// 创建Student类并实现Serializable接口,准备将该类的对象写入文件
class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class Demo1 {
public static void main(String[] args) throws IOException {
fun1();
}
public static void fun1() throws IOException {
/*
* 根据其构造方法
* ObjectOutputStream(OutputStream out)
* 传入的参数是OutputStream类型的
* 因为多态的存在
* 所以OutputStream类的子类类型都可以
*/
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f:\\Demo1.txt"));
Student s1 = new Person("Tom", 20);
oos.writeObject(s1);
oos.close();
}
}
3、实现对象的反序列化——读取对象
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException, IOException {
fun2();
}
public static void fun2() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f:\\Demo1.txt"));
// 直接向下强制转型为Student类
/*
* 注意readObject()方法会抛出两个异常:
* IOException,ClassNotFoundException
* 之所以会有ClassNotFoundException
* 是因为对象是依赖于其所属类的字节码文件(类名.class)的
* 因此在读取对象时,
* 必须要求其所属类的字节码文件也存在
*/
Student obj = (Student) ois.readObject();
System.out.println(obj.getName() + "," + obj.getAge());
ois.close();
}
}
4、Serializable接口
1.序列号:
在写入对象时,对象所属的类实现的Serializable接口会在该类内部同时写入一个唯一的UID序列号,以便找到该类;如果在写入对象完成之后,修改了该类中的任意内容,那么序列号也会随之改变,会导致找不到该类,从而引发异常。因此在处理对象的序列化时,建议声明自己的UID,例如:
static final long serialVersionUID = 42L;
这样不论该类内部怎样发生变化,都不会改变序列号。
2.transient:
例如对象在网络中传输也需要实现序列化,但如果希望某个元素不在网络中传输以节省流量,即不参与默认的序列化过程,可将其修饰为:
private transient int age;
这样Student类对象的年龄属性就不会被存储,从而实现了不参与序列化,最终返回的是该属性的默认值。
但不参与虚拟机默认的序列化不代表不能被序列化,可以手动实现参与序列化过程,将readObject()方法和writeObject()方法的方法签名添加到对应类中,代码如下:
class Student implements Serializable {
private String name;//可以默认进行序列化
private transient int age;//需要手动实现序列化
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
//添加writeObject()的方法签名
private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException{
s.defaultWriteObject();//将可以默认实现序列化的元素进行序列化操作
s.writeObject(age);//手动实现age的序列化
}
//添加readObject()的方法签名
private void readObject(java.io.ObjectInputStream s)throws java.io.IOException,ClassNotFoundException{
s.defaultReadObject();//将可以默认实现反序列化的元素进行反序列化操作
this.age = (int) s.readObject();//手动实现age的反序列化操作
}
}
实现手动控制某些元素是否参与序列化过程,目的是为了提高程序运行的性能,可以参考ArrayList的原码,在其定义的数组上修饰了transient,并不是不进行序列化,而是手动实现对有效数据进行序列化,反序列化同理,因此提高了程序的性能。
版权声明:欢迎转载,欢迎扩散,但转载时请标明作者以及原文出处,谢谢合作! ↓↓↓