一、序列化

将对象的状态存储到特定存储介质中的过程

对象序列化,就是把一个对象变为二进制的数据流的一种方法,通过对象序列化可以方便的实现对象的传输或存储。
 
序列化保存对象的“全景图”,构建对象的“全景天窗”.
如果一个类的对象想被序列化,则对象所在的类必须实现java.io.Serializable接口

二、对象的序列化和反序列化

要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream)
使用对象输出流输出序列化对象的步骤,有时也称为序列化,而使用对象输入流读入对象的过程,有时也称为反序列化
序列化步骤:
  1. 创建一个对象输出流ObjectOutputStream
  2. writeObject()方法输出序列化对象

反序列化步骤:

  1. 创建一个对象输入流ObjectInputStream
  2. readObject()方法读取流中的对象

三、对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream)

3.1、对象输出流:ObjectOutputStream

No.
方法或常量
类型
描述
1
public ObjectOutputStream(OutputStream out) throws IOException
构造
传入输出的对象
2
public final void writeObject(Object obj) throws IOException
普通
输出对象
此类的使用形式与PrintStream非常的相似,在实例化时也需要传入一个OutputStream的子类对象,之后根据传入的OutputStream子类的对象不同,输出的位置也不同。

3.2、对象输入流:ObjectInputStream

No.
方法或常量
类型
描述
1
public ObjectInputStream(InputStream in) throws IOException
构造
构造输入对象
2
public final Object readObject() throws IOException, ClassNotFoundException
普通
从指定位置读取对象
此类也是InputStream的子类,与PrintStream类的使用类似,此类同样需要接收InputStream类的实例才可以实例化

四、transient关键字

当使用Serializable接口实现序列化操作时,如果一个对象中的某个属性不希望被序列化的话,则可以使用transient关键字进行声明

import java.io.Serializable;
public class Person implements Serializable { // 此类的对象可以被序列化
private transient String name; // 此属性将不被序列化
private int age; // 此属性将被序列化
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() { // 覆盖toString(),输出信息
return "姓名:" + this.name + ";年龄:" + this.age;
}
}

五、实现反序列化注意事项

  • 反序列化过程无需要使用构造器生成对象
  • 按顺序反序列化恢复对象
  • 父类Serializable或者存在无参数构造方法

六、例子

package com.pb.serializable;

import java.io.Serializable;

/*
* 学生类 并实现接口Serializable接口,使用之可以序列化
*/
/*
* 序列化
* 1.创建一个对象,这个对象将被序列化,并写入文件中,前提是这个类实现了Serializable接口
* 2.实例化ObjectOutputStream的对象
* 3.调用ObjectOutputStream的writerObject()方法,将对象写入流中
* 4.关闭流
* transient关键字
* 可以保护对象中的敏感信息不被写入到文件中
* 反序列化
* 1.实例化ObjectInputStream对象
* 2.调用ObjectInputStream的readObject()方法,获取对象时,要进行强制类型转换
* 3.关闭流
*/
public class Student implements Serializable {
private String name; // 姓名
private int age; // 年龄
private String gender; // 性别
private transient String password; // 密码属性不能被序列化 // 构造方法
public Student() {
// 无参
} // 有参数
public Student(String name, int age, String gender, String password) { this.name = name;
this.age = age;
this.gender = gender;
this.password = password;
}
//getter、setter方法 public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
if(age>0&&age<150)
this.age = age;
} public String getGender() {
return gender;
} public void setGender(String gender) {
if(gender.equals("男") || gender.equals("女"))
this.gender = gender;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} // 自我介绍
public void say() {
System.out.println("姓名:" + this.name + "\t年龄:" + this.age + "\t性别:"
+ this.gender+"\t密码 : "+this.password);
} }

序列化:

package com.pb.serializable;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List; /*
* 序列化
* 1.创建一个对象,这个对象将被序列化,并写入文件中,前提是这个类实现了Serializable接口
* 2.实例化ObjectOutputStream的对象
* 3.调用ObjectOutputStream的writerObject()方法,将对象写入流中
* 4.关闭流
* transient关键字
* 可以保护对象中的敏感信息不被写入到文件中
*/
public class SerializableObj { public static void main(String[] args) { try {
//1.声明一个文件输出流
FileOutputStream fos = new FileOutputStream("d:/test/obj.txt");
//2.声明ObjectOutputStream流对象
ObjectOutputStream oos=new ObjectOutputStream(fos);
//也可以2步合一步
//ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("d:/test/obj.txt"));
Student stu1=new Student("张三", 23, "男", "123456");
Student stu2=new Student("李四", 24, "女", "123123");
Student stu3=new Student("王五", 25, "男", "123321");
Student stu4=new Student("赵六", 26, "男", "999999");
//创建集合并添加
List<Student> list=new ArrayList<Student>();
list.add(stu1);
list.add(stu2);
list.add(stu3);
list.add(stu4);
//3.将student对象序列化,写入输出oos流
oos.writeObject(stu1);
oos.writeObject(stu2);
oos.writeObject(stu3);
oos.writeObject(stu4);
oos.writeObject(list);
//4.关闭流
oos.close();
fos.close();
System.out.println("=======序列化完成======");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} } }

反序列化:

package com.pb.serializable;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List; /*
* 反序列化
* 1.实例化ObjectInputStream对象
* 2.调用ObjectInputStream的readObject()方法,获取对象时,要进行强制类型转换
* 3.关闭流
*/
public class ReadSerializableObj { public static void main(String[] args) { try {
//1.声明一个文件输出流
FileInputStream fis = new FileInputStream("d:/test/obj.txt");
//2.实例化ObjectInputStream
ObjectInputStream ois=new ObjectInputStream(fis);
//也可以全2为一
//ObjectInputStream ois=new ObjectInputStream(new FileInputStream("d:/test/obj.txt"));
//3.声明一个Student对象和集合
System.out.println("=====反序列化学生对象=======");
Student stu1= (Student) ois.readObject();
stu1.say();
Student stu2= (Student) ois.readObject();
stu2.say();
Student stu3= (Student) ois.readObject();
stu3.say();
Student stu4= (Student) ois.readObject();
stu4.say();
System.out.println("=====反序列化集合对象=======");
List<Student> list=(List<Student>) ois.readObject();
for (Student s : list) {
s.say();
} //4.关闭流
ois.close();
fis.close();
System.out.println("====反序列完成====");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} } }

结果:

=====反序列化学生对象=======
姓名:张三 年龄:23 性别:男 密码 : null
姓名:李四 年龄:24 性别:女 密码 : null
姓名:王五 年龄:25 性别:男 密码 : null
姓名:赵六 年龄:26 性别:男 密码 : null
=====反序列化集合对象=======
姓名:张三 年龄:23 性别:男 密码 : null
姓名:李四 年龄:24 性别:女 密码 : null
姓名:王五 年龄:25 性别:男 密码 : null
姓名:赵六 年龄:26 性别:男 密码 : null
====反序列完成====

从结果中可以看到:password使用transient关键字后,没有被序列化,反序列化中,读出的是默认字段类型的默认值null

七、包含引用类型属性的对象序列化

引用类必须也为可序列化

public class Teacher implements Serializable {
private String name; // 姓名
private int age; // 年龄
private String gender; // 性别
private transient String password; // 密码属性不能被序列化 private Student stu; //这里的Student类必须也是可以序列化的, }

这里有个Teacher类,但属性中有一个Student类的对象,这时Teacher要实现序列时,Student必须也要实现Serializable接口才可以

7.1、序列化算法

  • 对象分配序列号
  • 当程序试图序列化一个对象时,将会检查是否已经被序列化,只有序列化后的对象才能被转换成字节序列输出
  • 如果对象已经被序列化,则程序直接输出一个序列化编号,而不在重新序列化

7.2、序列化机制

Teacher类:

package com.pb.serializable;

import java.io.Serializable;
/*
* 教师类实例Serializable接口
*/
public class Teacher implements Serializable {
private String name; // 姓名
private int age; // 年龄
private String gender; // 性别
private transient String password; // 密码属性不能被序列化 private Student stu; //这里的Student类必须也是可以序列化的, //构造方法
public Teacher() {
//无参数
} public Teacher(String name, int age, String gender, String password,
Student stu) {
//有参数
this.name = name;
this.age = age;
this.gender = gender;
this.password = password;
this.stu = stu;
} //getter、setter方法
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 getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public Student getStu() {
return stu;
} public void setStu(Student stu) {
this.stu = stu;
} // 自我介绍
public void say() {
System.out.println("姓名:" + this.name + "\t年龄:" + this.age + "\t性别:"
+ this.gender+"\t密码 : "+this.password);
} }

序列化和化序列化类:

package com.pb.serializable;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; /*
* 老师类的序列化和反序列化 2个老师引用同一个学生对象
*/
public class WriterTeacherObj { public static void main(String[] args) { /*
* 序列化
* 1.序列化时时候,会查找当前对象的序列化编号是否存在,不存在,保存该对象
* 2.写入操作时,当对象的序列化编号存在时候,会输出一个当前对象的序列化编号,而不是当前对象
* 3.反序列化对象时, 程序会自动查找,当前对象的序列化编号,之后如果,发现当前的对象的序列化编号被其它对象引用时,则返回同一个对象
*/
try {
//1.实例化ObjectOutputStream
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("d:/test/teacher.txt"));
//2.实例化老师对象
Student student=new Student("马达", 23, "男", "123123");
//2个老师引用同一个学生对象
Teacher teacher_han=new Teacher("韩冰", 22, "女", "123456789", student);
Teacher teacher_zhang=new Teacher("张三丰", 108, "男", "123456789", student);
//3.对象序列
oos.writeObject(teacher_han);
oos.writeObject(teacher_zhang);
//4.关闭流
oos.close();
System.out.println("====================序列化完成=================");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*
* 反序列化
*/
System.out.println("==================开始反序列化================");
try {
//1.实例化ObjectInputStream对象
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("d:/test/teacher.txt"));
//2.反序列声明一个Teacher对象强制类型转换
Teacher teacher_han=(Teacher) ois.readObject();
Teacher teacher_zhang=(Teacher) ois.readObject();
//3.输入Teacher中的信息
System.out.println("==================老师信息================");
teacher_han.say();
teacher_zhang.say();
System.out.println("=================老师中学生信息=============");
teacher_han.getStu().say();
teacher_zhang.getStu().say();
//4.关闭流
ois.close();
System.out.println("===========反序列化完成========="); //判断2个老师的学生是否为同一个
if(teacher_han.getStu()==teacher_zhang.getStu()){
System.out.println("张老师和韩老师教的是同一个学生");
}else{
System.out.println("张老师和韩老师教的不是同一个学生");
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} } }

结果:

====================序列化完成=================
==================开始反序列化================
==================老师信息================
姓名:韩冰 年龄:22 性别:女 密码 : null
姓名:张三丰 年龄:108 性别:男 密码 : null
=================老师中学生信息=============
姓名:马达 年龄:23 性别:男 密码 : null
姓名:马达 年龄:23 性别:男 密码 : null
===========反序列化完成=========
张老师和韩老师教的是同一个学生

Java从零开始学三十九(对象序列化)的更多相关文章

  1. Java从零开始学三十八(JAVA IO- 重定向IO)

    一.三个静态变量 java.lang.System提供了三个静态变量 System.in(默认键盘) System.out(默认显示器) System.err 二.重写向方法 System提供了三个重 ...

  2. Java从零开始学三十六(JAVA IO- 字符流)

    一.字符流 BufferedReader:BufferedReader是从缓冲区之中读取内容,所有的输入的字节数据都将放在缓冲区之中 BufferedWriter:把一批数据写入到缓冲区,当缓冲区区的 ...

  3. Java从零开始学三十五(JAVA IO- 字节流)

    一.字节流 FileOutputStream是OutputStream 的直接子类 FileInputStream也是InputStream的直接子类 二.文本文件的读写 2.1.字节输入流 Test ...

  4. Java从零开始学三十三四(JAVA IO-流简述)

    一.流概念(stream) File类并不能对文件内容进行读写. 读文件就是指:把文件的内中的数据读取到内存中来 写文件就是指:把内存中的数据写入到文件中去. 通过什么读写文件呢?文件流. 1.1.流 ...

  5. Java从零开始学三十二(正则表达式)

    一.为什么要有正则 正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证.拆份.替换功能. 例如:现在要求判断一个字符串是否由数字组成,则可以有以下的两种做法: 不使用正则完成 使用正则完 ...

  6. Java从零开始学三十(String和StringBuffer类)

    一.StringBuffer连接字符操作 当一个字符串的内容需要被经常改变时就要使用StringBuffer 在StringBuffer中使用append()方法,完成字符串的连接操作   二.Str ...

  7. Java从零开始学二十九(大数操作(BigIntger、BigDecimal)

    一.BigInteger 如果在操作的时候一个整型数据已经超过了整数的最大类型长度long的话,则此数据就无法装入,所以,此时要使用BigInteger类进行操作. 不可变的任意精度的整数.所有操作中 ...

  8. Java从零开始学十一(类和对象)

    一.面象对象 二.什么是类 我肯定说,不知道.不清楚. 简单讲类是java中的基本单元,类是具有相同特性和行为的对象集合 三.类的定义 3.1.类的定义 class 类名称{ 数据类型  属性 ; … ...

  9. Java从零开始学四十五(Socket编程基础)

    一.网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可 ...

随机推荐

  1. BZOJ 1029: [JSOI2007]建筑抢修 优先队列

    1029: [JSOI2007]建筑抢修 Time Limit: 4 Sec  Memory Limit: 162 MB 题目连接 http://www.lydsy.com/JudgeOnline/p ...

  2. BZOJ 2330 SCOI2011糖果 差分约束

    2330: [SCOI2011]糖果 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2819  Solved: 820 题目连接 http://www ...

  3. UVALive 4426 Blast the Enemy! 计算几何求重心

    D - Blast the Enemy! Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Subm ...

  4. ASP.NET 构建高性能网站 第3篇

    HTTP请求的优化 在一个网页的请求过程中,其实整个页面的html结构(就是页面的那些html骨架)请求的时间是很短的,一般是占整个页面的请求时间的10%-20%.在页面加载的其余的时间实际上就是在加 ...

  5. 知识共享 - creative commons

    Creative Commons,简称CC,中国大陆正式名称为知识共享,台湾正式名称为创用CC. 是一个非营利组织,也是一种创作的授权方式. 此组织的主要宗旨是增加创意作品的流通可及性,作为其他人据以 ...

  6. 【《Objective-C基础教程 》笔记ch03】(四)OC中的OOP

    一.声明类接口步骤: 1.声明一个类接口,使用@interfacekeyword加上类名称. 2.用  { 实例变量 }  来定义各种数据成员. 3.方法声明,採用中缀符语法声明一个c函数,用到了冒号 ...

  7. nyoj 164&amp;&amp;poj2084 Game of Connections 【卡特兰】

    题意:将1~2n个数依照顺时针排列好.用一条线将两个数字连接起来要求:线之间不能有交点.同一个点仅仅同意被连一次. 最后问给出一个n,有多少种方式满足条件. 分析: ans[n]表示n的中的种类数. ...

  8. MySQL连接查询(inner join,left join和right join的区别)

    关系数据库由多个相关表组成,这些表使用已知为外键列的常用列链接在一起. 因此,从业务角度来看,每个表中的数据是不完整的. 例如,在示例数据库(yiibaidb)中,使用orderNumber列链接的o ...

  9. sqlite3.exe 使用

    1 下载sqlite3.exe 2 命令行cmd,进入到sqlite3.exe目录 3 >sqlite3.exe database.db   来打开sqlite数据库. 4 基本语法: > ...

  10. JDK1.6官方下载_JDK6官方下载

    JDK1.6官方下载_JDK6官方下载地址: http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin ...