概念
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
序列化步骤
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。
序列化的对象需要调用implements Serializable接口做一个标记
反序列化步骤
1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法读取对象。
部分属性序列化
实现部分字段序列化的方式:
- 使用transient修饰后该属性不会被序列化
- 使用static修饰后该属性不会被序列化
- 自定义方法writeObject和readObject
修改默认方法
在对象类中修改方法,想要哪些属性不序列化就写上哪些属性
Externalizable接口实现序列化和反序列化
用Externalizable自定义方法是定义哪个属性,哪个属性就会序列化进去
案例
快递柜项目,用序列化和反序列化
首先创建视图
public class Views {
private Scanner sc = new Scanner(System.in);
//欢迎
public void welcome() {
System.out.println("欢迎使用快递柜!");
}
//再见
public void bye() {
System.out.println("欢迎下次使用,再见!");
}
//主界面,选择相对应得身份使用
public int menu() {
System.out.println("请根据提示,输入功能序号:");
System.out.println("1.快递员");
System.out.println("2.用户");
System.out.println("0.退出");
String text = sc.nextLine();
int num = -1;
try {
num = Integer.parseInt(text);
} catch (NumberFormatException e) {
}
if (num < 0 || num > 2) {
System.out.println("输入得序号有误,请重新输入");
return menu();
}
return num;
}
//快递员界面
public int cmenu() {
System.out.println("请根据提示,输入功能序号:");
System.out.println("1.快递录入");
System.out.println("2.快递修改");
System.out.println("3.快递删除");
System.out.println("4.查询所有快递");
System.out.println("0.返回上级目录");
String text = sc.nextLine();
int num = -1;
try {
num = Integer.parseInt(text);
} catch (NumberFormatException e) {
}
if (num < 0 || num > 4) {
System.out.println("输入的序号有误,请重新输入");
return cmenu();
}
return num;
}
/**
* 快递录入
*
* @return 返回快递单号和快递公司
*/
public Express insert() {
System.out.println("请根据提示输入快递信息:");
System.out.println("请输入快递单号:");
String number = sc.nextLine();
System.out.println("请输入快递公司:");
String company = sc.nextLine();
Express e = new Express();
e.setNumber(number);
e.setCompany(company);
return e;
}
/**
* 修改快递
*
* @param e
*/
public Express update(Express e) {
Express e2 = new Express();
System.out.println("请输入新的快递单号");
String number = sc.nextLine();
System.out.println("请输入新的快递公司");
String company = sc.nextLine();
e2.setCompany(company);
e2.setNumber(number);
return e2;
}
/**
* 快递删除
*
* @return
*/
public int delete() {
System.out.println("是否确认删除:");
System.out.println("1.确认删除");
System.out.println("2.取消操作");
System.out.println("0.退出");
String text = sc.nextLine();
int num = -1;
try {
num = Integer.parseInt(text);
} catch (NumberFormatException e) {
}
if (num < 0 || num > 2) {
System.out.println("请重新输入正确的序号:");
return delete();
}
return num;
}
/**
* 将给定的数组里面的快递信息遍历显示
*
* @param
*/
public void printAll(Map map) {
int count = 0;
Iterator<Express> iterator = map.values().iterator();
while (iterator.hasNext()) {
count ++;
Express next = iterator.next();
System.out.println("快递信息为:" + "快递单号:" + next.getNumber() + "公司名称:" + next.getCompany() + "取件码:" + next.getCode());
}
if (count == 0) {
System.out.println("暂无快递信息");
}
}
/**
* 打印快递
*
* @param e
*/
public void printExpress(Express e) {
System.out.println("快递信息如下:");
System.out.println("快递公司:" + e.getCompany() + ",快递单号:" + e.getNumber() + ",取件码:" + e.getCode());
}
/**
* 查找快递单号,以后后续操作
*
* @return
*/
public String findNumber() {
System.out.println("请输入要操作的快递单号:");
String number = sc.nextLine();
return number;
}
/**
* 显示快递不存在
*/
public void printNull() {
System.out.println("快递不存在!");
}
/**
* 用户界面
*
* @return
*/
public int uMenu() {
System.out.println("请根据提示,进行取件");
System.out.println("请输入您的取件码:");
String code = sc.nextLine();
int num = -1;
try {
num = Integer.parseInt(code);
} catch (NumberFormatException e) {
}
if (num < 100000 || num > 999999) {
System.out.println("输入的数值有误,请输入六位数的取件码");
return uMenu();
}
return num;
}
/**
* 快递已存在
*/
public void expressExist() {
System.out.println("此快递在快递柜中已存在,请勿重复存储。");
}
/**
* 打印取件码
*
* @param e
*/
public void printCode(Express e) {
System.out.println("快递取件码为:" + e.getCode());
}
public void success() {
System.out.println("操作成功");
}
}
创建快递对象
import java.io.Serializable;
import java.util.Objects;
/**
* @ Since : 1.0
* @ Author: DAJ
* @ Date : 13:13 2021/4/4
*
* 快递对象属性
*/
public class Express implements Serializable {
//单号
private String number;
//公司名称
private String company;
//取件码
private int code;
public Express() {
}
public Express(String number, String company, int code) {
this.number = number;
this.company = company;
this.code = code;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
@Override
public String toString() {
return "Express{" +
"number='" + number + '\'' +
", company='" + company + '\'' +
", code=" + code +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Express express = (Express) o;
return code == express.code &&
Objects.equals(number, express.number) &&
Objects.equals(company, express.company);
}
@Override
public int hashCode() {
return Objects.hash(number, company, code);
}
}
定义快递对象调用方法
import com.kaikeba.worktestio.test.bean.Express;
import java.io.*;
import java.util.*;
/**
* @ Since : 1.0
* @ Author: DAJ
* @ Date : 14:46 2021/4/4
*/
public class ExpressDao {
//创建一个集合用来存储快递信息,键值为快递单号
private Map<String, Express> map;
public void setMap(Map<String, Express> map) {
this.map = map;
}
//存储当前的快递数
private int size;
//创建随机数
private Random random = new Random();
public Map add(Express e) {
//存满了
if (size == 100) {
return null;
}
if (null != map.get(e.getNumber())){
return null;
}
//2.取件码
int code = randomCode();
e.setCode(code);
//存入到集合中去
map.put(e.getNumber(), e);
return map;
}
/**
* 生成取件码
*
* @return
*/
private int randomCode() {
while (true) {
//生成六位随机取件码
int code = (int) ((Math.random() * 9 + 1) * Math.pow(10, 5));
Express byCode = findByCode(code);
if (byCode == null) {
return code;
}
}
}
/**
* 根据取件码查快递
*
* @param code
* @return
*/
public Express findByCode(int code) {
//根遍历values值查找快递,使用迭代器
Iterator<Express> iterator = map.values().iterator();
while (iterator.hasNext()) {
Express next = iterator.next();
if (next.getCode() == code) {
return next;
}
}
return null;
}
/**
* 根据快递单号查快递
*
* @param number
* @return
*/
public Express finByNumber(String number) {
return map.get(number);
}
/**
* 修改快递信息
*
* @param
*/
public Map update(Express oldExpress, Express newExpress) {
delete(oldExpress.getNumber());
Map add = add(newExpress);
return add;
}
/**
* 删除快递信息
*
* @param number
*/
public Map delete(String number) {
map.remove(number);
return map;
}
public Map findAll() {
return map;
}
/**
* 将对象序列化到指定文件中
* @param map
* @param fileName
*/
public void mySerializable(Map map, String fileName) throws IOException {
OutputStream os = new FileOutputStream(fileName);
ObjectOutputStream obs = new ObjectOutputStream(os);
obs.writeObject(map);
obs.close();
}
/**
* 从指定文件中反序列化
* @param fileName
* @return
*/
public Map myDesSerializable(String fileName) throws IOException, ClassNotFoundException {
File file =new File(fileName);
if (!file.exists()){
return new HashMap();
}
InputStream is = new FileInputStream(fileName);
Map map = null;
if (file.length() > 0){
ObjectInputStream ois = new ObjectInputStream(is);
map= (Map) ois.readObject();
return map;
}
return new HashMap();
}
}
主方法调用
import com.kaikeba.worktestio.test.bean.Express;
import com.kaikeba.worktestio.test.dao.ExpressDao;
import com.kaikeba.worktestio.test.view.Views;
import java.io.IOException;
import java.util.Map;
public class Main {
//初始化视图对象
private static Views v = new Views();
//初始化dao对象
private static ExpressDao dao = new ExpressDao();
private static String filename = "e://hh//express.txt";
public static void main(String[] args) throws IOException, ClassNotFoundException {
//调用反序列化取得map集合
dao.setMap(dao.myDesSerializable(filename));
//1.欢迎
v.welcome();
m:
while (true) {
//2.弹出主界面
int menu = v.menu();
switch (menu) {
case 0:
break m;
case 1:
//调用快递员操作
cClient();
break;
case 2:
//调用用户操作
uClient();
break;
}
}
//使用结束
v.bye();
}
private static void cClient() {
while (true) {
int menu = v.cmenu();
switch (menu) {
case 0:
return;
case 1: {//1.快递录入
Express e = v.insert();
//2.此快递是否已经存储过
Express express = dao.finByNumber(e.getNumber());
//3.存储快递
if (express == null) {
//未存储,把快递存进去
Map add = dao.add(e);
try {
dao.mySerializable(add,filename);
} catch (IOException e1) {
e1.printStackTrace();
}
//存进去之后将快递信息打印出来
v.printExpress(e);
}else
v.expressExist();
}
break;
case 2: {//2.快递修改
//1.调用视图显示
String number = v.findNumber();
//2.查找数据
Express e = dao.finByNumber(number);
//Express e2 = e;
//3.打印快递信息
if (e == null) {
v.printNull();
} else {
v.printExpress(e);
//4.提示修改
Express e2 = v.update(e);
//将老的数据删除,新的数据添加上去
Map update = dao.update(e, e2);
try {
dao.mySerializable(update,filename);
} catch (IOException e1) {
e1.printStackTrace();
}
//打印修改后得快递信息
v.printExpress(e2);
}
}
break;
case 3: {//3.删除
//1.输入快递单号
String number = v.findNumber();
//2.根据输入得快递单号查找快递对象
Express e = dao.finByNumber(number);
if (e == null) {
v.printNull();
} else {
v.printExpress(e);
//询问用户是否要删除,1为确认删除
int type = v.delete();
if (type == 1) {
Map delete = dao.delete(number);
try {
dao.mySerializable(delete,filename);
} catch (IOException e1) {
e1.printStackTrace();
}
v.success();
}
}
}
break;
case 4: {//查看所有
Map all = dao.findAll();
v.printAll(all);
}
break;
}
}
}
private static void uClient() {
//1.先调用视图里面用户取件得流程
int code = v.uMenu();
//2.在调用方法去取件
Express e = dao.findByCode(code);
if (e == null) {
v.printNull();
} else {
v.success();
v.printExpress(e);
Map delete = dao.delete(e.getNumber());
try {
dao.mySerializable(delete,filename);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}