对象的序列化与反序列化
序列化:把对象转换为字节序列的过程
反序列化:把字节序列恢复为对象的过程
什么情况下需要序列化:
1、当你想把的内存中的对象状态保存到一个文件中或者数据库中时候
2、当你想用套接字在网络上传送对象的时候
3、当你想通过RMI传输对象的时候
JDK类库中的序列化API
java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。 只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可
以采用默认的序列化方式 。
对象序列化包括如下步骤:
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。
对象反序列化的步骤如下:
1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法读取对象。
示例:
public class PhoneNumber implements Serializable{
private static final long serialVersionUID = 1L;
private final short areaCode;
private final short prefix;
private final short lineNumber;
public PhoneNumber(short areaCode, short prefix, short lineNumber) {
this.areaCode = areaCode;
this.prefix = prefix;
this.lineNumber = lineNumber;
}
@Override
public boolean equals(Object o) {
if(o == this) {
return true;
}
if(!(o instanceof PhoneNumber)) {
return false;
}
PhoneNumber number = (PhoneNumber)o;
return number.lineNumber == lineNumber &&
number.prefix == prefix &&
number.areaCode == areaCode;
}
}
public class TestSerializable {
public static void main(String[] args) throws Exception, IOException {
serializable();
PhoneNumber p = Deserializable();
System.out.println(p);
}
private static void serializable() throws IOException {
ObjectOutputStream ob = new ObjectOutputStream(new FileOutputStream("D://PhoneNumber.txt"));
PhoneNumber p = new PhoneNumber((short)100,(short)101,(short)102);
ob.writeObject(p);
}
private static PhoneNumber Deserializable() throws ClassNotFoundException, IOException {
ObjectInputStream oi = new ObjectInputStream(new FileInputStream("D://PhoneNumber.txt"));
PhoneNumber p = (PhoneNumber) oi.readObject();
return p;
}
}
序列化PhoneNumber成功后在D盘生成了一个PhoneNumber.txt文件,而反序列化PhoneNumber是读取D盘的PhoneNumber.txt后生成了一个PhoneNumber对象.
serialVersionUID的作用
serialVersionUID: 字面意思上是序列化的版本号,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量
serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。
显式地定义serialVersionUID有两种用途:
1、 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
2、 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。
如果将上例中的PhoneNumber的serialVersionUID注释掉,并且在PhoneNumber中添加一个childPhoneNUmber域,这个时候再去利用生成的PhoneNumber.txt反序列化PhoneNumber,也会报异常。但是如果解除serialVersionUID的注释,则可以正常反序列化。
将上面示例的serialVersionUID改为2L,这个时候再去利用生成的PhoneNumber.txt反序列化PhoneNumber,也会导致InvalidClassException。
上一篇: 实现将某个目录所有内容拷贝到另一个目录下
下一篇: python抽象类