一、序列化

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

对象序列化,就是把一个对象变为二进制的数据流的一种方法,通过对象序列化可以方便的实现对象的传输或存储。
 
序列化保存对象的“全景图”,构建对象的“全景天窗”.
如果一个类的对象想被序列化,则对象所在的类必须实现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. nlogn 求最长上升子序列 LIS

    最近在做单调队列,发现了最长上升子序列O(nlogn)的求法也有利用单调队列的思想. 最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]& ...

  2. opencv 支持向量机SVM分类器

    支持向量机SVM是从线性可分情况下的最优分类面提出的.所谓最优分类,就是要求分类线不但能够将两类无错误的分开,而且两类之间的分类间隔最大,前者是保证经验风险最小(为0),而通过后面的讨论我们看到,使分 ...

  3. BlueMind 3.0.17 发布,消息和协作平台

    BlueMind 3.0.17 发布,此版本对即时消息 Web 应用连接处理做了较大改进(更可靠),还修复了通讯录浏览器. BlueMind 3.0.17 现已提供下载. 详细改进记录如下: Addr ...

  4. [Linux] Ubuntu 18 LTS netplan 网络配置

    Ubuntu 18 LTS netplan 网络配置 今天装完 Ubuntu 18 LTS,配置网络时发现Ubuntu 18LTS ifupdown has been replaced by netp ...

  5. Syslink Control in MFC 9.0(转)

    Visual Studio 2008 (formely code-named ‘Orcas’) has several important updates for VC++ and MFC. Amon ...

  6. oracle sql语句怎么查询所有存储过程中是否包含某个注释?

    select text from all_source where type='PROCEDDURE' and name='过程名'and instr(text,'注释内容')>0

  7. Oracle体系结构及备份(十六)——bg-ckpt

    一  什么是CKPT进程 作用: 发出信号给DBWn 更新数据文件头 更新控制文件 At specific times, all modified databasebuffers in the sys ...

  8. SOLARIS 11G 安装 ORACLE 11G

    https://docs.oracle.com/cd/E11882_01/install.112/e48357/pre_install.htm#SSDBI1209 http://blog.chinau ...

  9. How to check Ubuntu version

    Below you can find some tips on how to check Ubuntu version you are currently running. The first pla ...

  10. Java基础加强总结(二)——泛型

    一.体验泛型 JDK1.5之前的集合类中存在的问题——可以往集合中加入任意类型的对象,例如下面代码: package cn.gacl.generic.summary; import java.util ...