Serializable
什么是serializable接口
一个对象序列化的接口,一个类只有实现了Serializable接口,才可以被序列化
什么是序列化
将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将其当前状态写入到临时存储区或者持久性存储区,之后,便可以通过从存储区中读取或反序列化 它自动屏蔽了操作系统的差异,字节顺序等。比如,在 Windows 平台生成一个对象并序列化之,然后通过网络传到一台 Unix 机器上,然后可以在这台Unix机器上正确地重构(deserialization)这个对象。 不必关心数据在不同机器上如何表示,也不必关心字节的顺序或者其他任何细节。
什么时候需要序列化
当我需要把对象的状态信息通过网络进行传输,或者需要将对象的状态信息持久化,以便将来使用时都需要把对象进行序列化
对象的序列化机制
对象的类,类签名,以及非瞬态和非静态字段的值(序列化不保存静态,因为他和类是同级的)
serivalVersionUID
序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会去检测文件中的serialVersionUID,判断它是否与当前类的serialVersionUID一致,如果一致就说明序列化类的版本与当前类版本是一样的,可以反序列化成功,否则失败。
显式声明
private static final long serialVersionUID = xxxxL;
如果没有显式地定义一个serialVersionUID,那么Java会默认根据类信息计算一个serivalVersionUID出来。如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化。
Java提供的Serializable是一个空接口,如果一个类实现了Serializable接口
代表这个类及其子类是自动支持序列化和反序列化的
序列化时,只对对象的状态进行保存,而不管对象的方法,如果一个类没有实现Serializable接口,那么默认是不能被序列化的,除非使用其他方式
如果一个类实现了Seralizable接口,而其父类没有实现Serializable接口,那么父类必须有无参的构造器,父类中的字段不参与序列化,只是将其初始化而已。
序列化的实例变量引用其他的对象,则引用的对象也会被序列化
并非所有的对象都可以序列化
一个Serializable(可序列化)对象进行重写装配的过程中,不会调用任何构造器(甚至默认构造器),整个对象都是通过InputStream中取得数据恢复的.
我们可能有特殊的安全问题,不希望对象的某一部分实例化;或者子类对象完全不必实例化,因为对象恢复后,拿一部分需要重新创建
通过实现Externalizable接口,用它代替Serializable,便可以控制序列化的具体过程.
Externalizable接口扩展了Serializable 并增加了两个方法writeExternal()和readExternal()
Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
根据父类对象序列化的规则,我们可以将不需要被序列化的字段抽取出来放到父类中,子类实现 Serializable 接口,父类不实现,根据父类序列化规则,父类的字段数据将不被序列化
谨慎地实现 Serialiable
为了继承而设计的类应该很少实现 Serialiable, 接口也应该很少会扩展它. 如果违反了这条规则, 则扩展这个类或者实现这个接口的程序员会背上沉重的负担.
若没有认真考虑默认序列化形式是否合适, 则不要接受这种形式
即使你确定了默认序列化形式是合适的, 通常你仍然要提供一个 readObject方法以保证约束关系和约束性
不管你选择了哪种序列化形式, 你都要为自己编写的每个可序列化的类声明一个显式的序列版本 UID (serialVersionUID)
对象实现序列化的步骤
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。
对象反序列化的步骤如下:
1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法读取对象。
Externalizable的例子
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* @Description: 学生类 已实现序列化接口
* @author yuanfy
* @date 2018年1月11日 上午11:36:37
* @version 1.0
*/
public class Student implements Externalizable{
private static final long serialVersionUID = 61234L;
private String name;
private transient int age;
private static String sex;
public Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// TODO Auto-generated method stub
out.writeUTF(name);
out.writeInt(age);
out.writeObject(sex);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.name = in.readUTF();
this.age = in.readInt();
this.sex = (String)in.readObject();
}
}
@Test
public void test3() throws FileNotFoundException, IOException, ClassNotFoundException{
Student s1 = new Student("james", 31, "man");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("E:\\Student.txt")));
oos.writeObject(s1);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:\\Student.txt")));
Student s2 = (Student)ois.readObject();
System.out.println(s2);
ois.close();
}
代码转载至https://www.cnblogs.com/yuanfy008/p/8269337.html
转载于:https://blog.51cto.com/10760006/2165123