1. Java序列化和反序列化
Java序列化是指将Java对象转化为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。 当两个进程进行远程通信时,这个通信的数据可以为文本、图片、音频或者视频等,而这些数据都是以二进制的形式进行传送的。而当两个Java进程间进行通信时,进程间对象的传送也是二进制方式传输。这就要用到序列化和反序列化,一方面,发送方需要把这个Java对象转化为字节序列,另一方面接收方要从字节序列中恢复出Java对象。
好处:
* 实现了数据的持久化,通过序列化可以把数据永久地存放在硬盘上
* 利用反序列化实现远程通信,即在网络上传送对象的字节序列化
2. 如何实现Java序列化和反序列化
2.1 JDK类库中序列化API
- java.io.ObjectOutputStream:表示对象输出流
它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
-java.io.ObjectInputStream:表示对象输入流-
它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回。
- 序列化步骤:
步骤一:创建一个对象输出流,它可以包装一个其它类型的目标输出流,如文件输出流:
ObjectOutputStream out = new ObjectOutputStream(new fileOutputStream(“D:\objectfile.obj”));
步骤二:通过对象输出流的writeObject()方法写对象:
out.writeObject(“Hello”);
out.writeObject(new Date());
- 反序列化步骤:
步骤一:创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流:
ObjectInputStream in = new ObjectInputStream(new fileInputStream(“D:\objectfile.obj”));
步骤二:通过对象输出流的readObject()方法读取对象:
String obj1 = (String)in.readObject();
Date obj2 = (Date)in.readObject();
2.2 实现序列化接口
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。
2.3 案例
import java.io.Serializable;
public class Student implements Serializable
{
private static final long serialVersionUID = 4603642343377807741L;
private String name;
private char sex;
private int year;
private double gpa;
public Student()
{
}
public Student(String name,char sex,int year,double gpa)
{
this.name = name;
this.sex = sex;
this.year = year;
this.gpa = gpa;
}
public void setName(String name)
{
this.name = name;
}
public void setSex(char sex)
{
this.sex = sex;
}
public void setYear(int year)
{
this.year = year;
}
public void setGpa(double gpa)
{
this.gpa = gpa;
}
public String getName()
{
return this.name;
}
public char getSex()
{
return this.sex;
}
public int getYear()
{
return this.year;
}
public double getGpa()
{
return this.gpa;
}
}
把Student类的对象序列化到文件D:\student.txt,并从该文件中反序列化,向console显示结果。代码如下:
import java.io.*;
public class UseStudent
{
public static void main(String[] args)
{
Student st = new Student("Tom",'M',20,3.6);
File file = new File("D:\\student.txt");
try
{
file.createNewFile();
}
catch(IOException e)
{
e.printStackTrace();
}
try
{
//Student对象序列化过程
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(st);
oos.flush();
oos.close();
fos.close();
//Student对象反序列化过程
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Student st1 = (Student) ois.readObject();
System.out.println("name = " + st1.getName());
System.out.println("sex = " + st1.getSex());
System.out.println("year = " + st1.getYear());
System.out.println("gpa = " + st1.getGpa());
ois.close();
fis.close();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
3.serialVersionUID的作用
serialVersionUID字面意思是序列化版本号,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量。Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
serialVersionUID的作用生成方式:
1.一个是默认的1L,比如:private static final long serialVersionUID = 1L;
2.一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段
++ 为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。 ++
参考博客:
http://kb.cnblogs.com/page/515982/
http://blog.csdn.net/abc6368765/article/details/51365838
http://blog.csdn.net/wangloveall/article/details/7992448/
http://kb.cnblogs.com/page/515982/