序列化
序列化指把内存中的Java对象转换成与平台无关的二进制字节序列,以便永久保存在磁盘上或者通过网络进行传输,是Java提供的一种将对象写入到输入流并在之后将其读回的机制。
所以序列化作用有两点:
- 便于保存对象信息于磁盘上
- 方便对象信息网络传输
- 序列化:将java对象转换为字节序列
- 反序列化:把字节序列回复为原先的java对象
序列化的实现
Java提供了对象流ObjectInputStream和ObjectOutputStream,可以将以对象形式存在于内存中的数据储存至文件,需要时再将其从文件中读出还原为对象,或者在网络上传送对象。
为了让某个类是可以序列化的,该类可以通过实现Serializable接口,该接口无具体方法,只需声明实现该接口,起到标识性意义,代表该对象是可以序列化的。
下面为一个是实例序列化
import java.io.Serializable;
//首先是序列化的类
public class Person implements Serializable {
private String name;
private int age;
private int id;
public Person(){}
public Person (String name,int age,int id){
this.name = name;
this.age = age;
this.id = id;
}
}
//实现序列化过程
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Test {
public static void main(String[] args) {
ObjectOutputStream out = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream("D:\\ͼƬ\\Tset.txt");
out = new ObjectOutputStream(fos);
Person p = new Person("张三",45,12);
out.writeObject(p);
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}finally{
try {
fos.close();
out.close() ;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
运行成功将Person类对象p保存在磁盘文件Test。txt中
//反序列化
import java.io.Serializable;
public class Person implements Serializable {
private String name;
private int age;
private int id;
public Person(){}
public Person(String name, int age, int id){
this.name = name;
this.age = age;
this.id = id;
}
public String toString(){//新添加方法
return this.name+this.age+this.id;
}
}
import Work.Person;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Test {
public static void main(String[] args) {
ObjectInputStream in = null;
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\ͼƬ\\Tset.txt");
in = new ObjectInputStream(fis);
Person p = (Person)in.readObject();
System.out.println(p);
} catch (Exception e) {
throw new RuntimeException(e);
}finally{
try {
fis.close();
in.close() ;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
按上次序列化生成的Test.txt文件反序列化,由异常出现
Exception in thread “main” java.lang.RuntimeException: java.io.InvalidClassException: Work.Person; local class incompatible: stream classdesc serialVersionUID = 6513129562756671272, local class serialVersionUID = 4654183961547435119
at Work.Test.main(Test.java:24)
serialVersionUID是序列化前后的唯一标识符
默认如果没有人为显式定义过serialVersionUID,那编译器会为它自动声明一个!
因为反序列化,我在Person类中增加了一个String方法,所以serialVersionUID序列化ID前后不一致
serialVersionUID可以看成是序列化和反序列化过程中的“暗号”,在反序列化时,JVM会把字节流中的序列号ID和被序列化类中的序列号ID做比对,只有两者一致,才能重新反序列化,否则就会报异常来终止反序列化的过程。
所以,为了serialVersionUID的确定性,写代码时还是建议,凡是implements Serializable的类,都最好人为显式地为它声明一个serialVersionUID明确值!
public static final long serialVersionUID=475463534532L;
//添加在Person类中
反序列化结果为:
注意:
transient修饰符的作用了(在实现Serializable接口的情况下
如果在序列化某个类的对象时,就是不希望某个字段被序列化(比如这个字段存放的是隐私值,如:密码等),那这时就可以用transient修饰符来修饰该字段。