Java从零开始学三十九(对象序列化)
一、序列化
将对象的状态存储到特定存储介质中的过程
二、对象的序列化和反序列化
- 创建一个对象输出流ObjectOutputStream
- writeObject()方法输出序列化对象
反序列化步骤:
- 创建一个对象输入流ObjectInputStream
- readObject()方法读取流中的对象
三、对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream)
3.1、对象输出流:ObjectOutputStream
No.
|
方法或常量
|
类型
|
描述
|
1
|
public ObjectOutputStream(OutputStream out) throws IOException
|
构造
|
传入输出的对象
|
2
|
public final void writeObject(Object obj) throws IOException
|
普通
|
输出对象
|
3.2、对象输入流:ObjectInputStream
No.
|
方法或常量
|
类型
|
描述
|
1
|
public ObjectInputStream(InputStream in) throws IOException
|
构造
|
构造输入对象
|
2
|
public final Object readObject() throws IOException, ClassNotFoundException
|
普通
|
从指定位置读取对象
|
四、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从零开始学三十九(对象序列化)的更多相关文章
- Java从零开始学三十八(JAVA IO- 重定向IO)
一.三个静态变量 java.lang.System提供了三个静态变量 System.in(默认键盘) System.out(默认显示器) System.err 二.重写向方法 System提供了三个重 ...
- Java从零开始学三十六(JAVA IO- 字符流)
一.字符流 BufferedReader:BufferedReader是从缓冲区之中读取内容,所有的输入的字节数据都将放在缓冲区之中 BufferedWriter:把一批数据写入到缓冲区,当缓冲区区的 ...
- Java从零开始学三十五(JAVA IO- 字节流)
一.字节流 FileOutputStream是OutputStream 的直接子类 FileInputStream也是InputStream的直接子类 二.文本文件的读写 2.1.字节输入流 Test ...
- Java从零开始学三十三四(JAVA IO-流简述)
一.流概念(stream) File类并不能对文件内容进行读写. 读文件就是指:把文件的内中的数据读取到内存中来 写文件就是指:把内存中的数据写入到文件中去. 通过什么读写文件呢?文件流. 1.1.流 ...
- Java从零开始学三十二(正则表达式)
一.为什么要有正则 正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证.拆份.替换功能. 例如:现在要求判断一个字符串是否由数字组成,则可以有以下的两种做法: 不使用正则完成 使用正则完 ...
- Java从零开始学三十(String和StringBuffer类)
一.StringBuffer连接字符操作 当一个字符串的内容需要被经常改变时就要使用StringBuffer 在StringBuffer中使用append()方法,完成字符串的连接操作 二.Str ...
- Java从零开始学二十九(大数操作(BigIntger、BigDecimal)
一.BigInteger 如果在操作的时候一个整型数据已经超过了整数的最大类型长度long的话,则此数据就无法装入,所以,此时要使用BigInteger类进行操作. 不可变的任意精度的整数.所有操作中 ...
- Java从零开始学十一(类和对象)
一.面象对象 二.什么是类 我肯定说,不知道.不清楚. 简单讲类是java中的基本单元,类是具有相同特性和行为的对象集合 三.类的定义 3.1.类的定义 class 类名称{ 数据类型 属性 ; … ...
- Java从零开始学四十五(Socket编程基础)
一.网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可 ...
随机推荐
- BZOJ 1029: [JSOI2007]建筑抢修 优先队列
1029: [JSOI2007]建筑抢修 Time Limit: 4 Sec Memory Limit: 162 MB 题目连接 http://www.lydsy.com/JudgeOnline/p ...
- BZOJ 2330 SCOI2011糖果 差分约束
2330: [SCOI2011]糖果 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2819 Solved: 820 题目连接 http://www ...
- UVALive 4426 Blast the Enemy! 计算几何求重心
D - Blast the Enemy! Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Subm ...
- ASP.NET 构建高性能网站 第3篇
HTTP请求的优化 在一个网页的请求过程中,其实整个页面的html结构(就是页面的那些html骨架)请求的时间是很短的,一般是占整个页面的请求时间的10%-20%.在页面加载的其余的时间实际上就是在加 ...
- 知识共享 - creative commons
Creative Commons,简称CC,中国大陆正式名称为知识共享,台湾正式名称为创用CC. 是一个非营利组织,也是一种创作的授权方式. 此组织的主要宗旨是增加创意作品的流通可及性,作为其他人据以 ...
- 【《Objective-C基础教程 》笔记ch03】(四)OC中的OOP
一.声明类接口步骤: 1.声明一个类接口,使用@interfacekeyword加上类名称. 2.用 { 实例变量 } 来定义各种数据成员. 3.方法声明,採用中缀符语法声明一个c函数,用到了冒号 ...
- nyoj 164&&poj2084 Game of Connections 【卡特兰】
题意:将1~2n个数依照顺时针排列好.用一条线将两个数字连接起来要求:线之间不能有交点.同一个点仅仅同意被连一次. 最后问给出一个n,有多少种方式满足条件. 分析: ans[n]表示n的中的种类数. ...
- MySQL连接查询(inner join,left join和right join的区别)
关系数据库由多个相关表组成,这些表使用已知为外键列的常用列链接在一起. 因此,从业务角度来看,每个表中的数据是不完整的. 例如,在示例数据库(yiibaidb)中,使用orderNumber列链接的o ...
- sqlite3.exe 使用
1 下载sqlite3.exe 2 命令行cmd,进入到sqlite3.exe目录 3 >sqlite3.exe database.db 来打开sqlite数据库. 4 基本语法: > ...
- JDK1.6官方下载_JDK6官方下载
JDK1.6官方下载_JDK6官方下载地址: http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin ...