前段时间和同事讨论序列化和反序列化的时候,对一些概念相互争论了很久,发现好多东西之前只是草草了解一下没有记录下来,一些概念性的东西似是而非,一旦时间长了不用就容易忘啊,今天抽出时间写写关于这方面的内容记录下来吧,毕竟好记性不如烂笔头。
首先明确一点,字节序列化和二进制序列化以及对象序列化表示的是同一个东西,因为一个字节代表八个二进制位字节本身也是由二进制组成的,但是以上三种说法代表的是同一个东西别搞混了。
接下来说下定义和序列化的作用:
序列化:将Java对象转化为字节序列
反序列化:与上面过程相反,将字节序列转化为对象
作用:一般有两个作用,第一个是将Java对象序列化字节后存储在本地硬盘进行持久化保存,另外一个作用是在远程通信的时候,Java对象是以字节流的的形式在网络上从传送的
明白了概念以及作用后接下来就看代码吧,其实代码也很简单,直接粘过来
public class Person implements Serializable {
private String name;
private char sex;
private int year;
private double age;
public Person(String name, char sex, int year, double age) {
super();
this.name = name;
this.sex = sex;
this.year = year;
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public double getAge() {
return age;
}
public void setAge(double age) {
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
Person p = new Person("zhangsan", '男', 1980, 37);
File f = new File("F:\\person.txt");
try {
f.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 将Person对象序列化的过程
try {
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(f));
oo.writeObject(p);
oo.flush();
oo.close();
// 将字节反序列化对象
ObjectInputStream oi = new ObjectInputStream(new FileInputStream(f));
Person p1 = (Person) oi.readObject();
System.out.println("读取序列化对象的名字: "+p1.getName());
System.out.println("读取序列化对象的性别: "+p1.getSex());
System.out.println("读取序列化对象的出生年份: "+p1.getYear());
System.out.println("读取序列化对象的年龄: "+p1.getAge());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
简单说一下代码,一个Java对象要实现序列化首先要对应的Java类实现Serializable接口,这是首要前提,其次,如果类的某个字段不想被序列化,那么在属性前面加上transient关键字,这样序列化的时候就会忽略该字段,具体形式类似于下图。
接下里说下序列化与反序列化过程:在序列化阶段就是将Java对象转化为字节序列存储在本地硬盘,一般是存放在一个文本文件中,用到了ObjectOutputStream和FileOutputStream这两个类,通过向指定的文件打开输出流,之后调用writeObject方法将指定的Java对象以字节序列的形式写入指定文本文件。而反序列化就是利用了ObjectInputStream和FileInputStream这两个类,从指定的本地文件打开输入流调用readObject方法读取,读取的内容是字节序列,之后转化为Object对象,在测试是否读取成功前要进行相应的类型转化。记得在操作完毕后记得关闭相应的输出流和输入流以免占用系统资源
存储在本地的文件内容大致是下面这个形式
sr com.aaa.test.Person4O堑d 涟 D ageC sexI yearL namet Ljava/lang/String;xp@B€ u7 紅 zhangsan
执行Test类的main方法,在控制台输出下面内容表明反序列化成功
读取序列化对象的名字: zhangsan
读取序列化对象的性别: 男
读取序列化对象的出生年份: 1980
读取序列化对象的年龄: 37.0
之前用transient关键字修饰了性别,那么其他的会正常输出,而性别会显示下面内容,也就是说性别这个字段被华丽的无视了
读取序列化对象的性别:
这只是一种实现序列化和反序列化的方式,另外还有两种,一种是实现Serializable接口的同时,如果字段加上transient关键字,可以在对应的Java类添加下面两个方法来继续序列化这个字段,同理可以序列化所有字段,不过这种方式比较麻烦,不推荐,另外一种是实现Externalizable接口,这种方式也不常见这里就不写了
private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
out.writeChar(sex);
}
private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException{
in.defaultReadObject();
sex=in.readChar();
}
至此Java对象的序列化与反序列化也就明白的差不多了,对了,另外补充两点:1.如果一个类实现了Serializable接口,那么它的子类不需要显示声明也可以被序列化 2.序列化仅可以序列化的是普通成员变量,无法序列化静态变量。OK结束