对象序列化
- 对象序列化的概念
- 将java对象转为二进制的方式,称为对象序列化
- 对象序列化以后会加快对象在网络上的传输效率和存储效率。
- 序列化的实现方式
1)自定义的实体类实现java.io.Serializable接口即可实现该对象的序列化。
2)对象保存磁盘的操作使用ObjectOutputStream对象进行存储。
ObjectOutputStream的使用方式
ObjectOutputStream os=new ObjectOutputStream(文件字节输出流);
os.writeObject(被序列化的对象);
os.flush();
os.close();
3)未经序列化的类对象,在存储时会出现NoSerializableException异常(未序列化异常)
4)序列化类的实现
package com.bean; import java.io.Serializable; public class Student implements Serializable { private int sid; private String sname; private String sex; private String address; private int age; public Student() { } public Student(int sid, String sname, String sex, String address, int age) { this.sid = sid; this.sname = sname; this.sex = sex; this.address = address; this.age = age; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
存储的示例:
package com.test; import java.io.*; import com.bean.*; public class StudentToFileDemo { public static void main(String[] args) { File file=new File("stu.bin"); try { FileOutputStream fout=new FileOutputStream(file); Student st=new Student(1,"武松","男","景阳冈",22); ObjectOutputStream objectOutputStream=new ObjectOutputStream(fout); objectOutputStream.writeObject(st); objectOutputStream.flush(); objectOutputStream.close(); System.out.println("保存成功!"); } catch (IOException e) { e.printStackTrace(); } } } |
- 反序列化
- 将存储或者在网络上传输的二进制序列化对象转为java类的对象进行使用。这种将序列化的二进制对象转为java类对象的过程称为范序列化。
- 使用ObjectInputStream类对象实现反序列化的操作。
ObjectInputStream oin=new ObjectInputStream(文件输入流对象);
Object obj=oin.readObject();
- 使用示例
package com.test; import java.io.*; import java.lang.reflect.AnnotatedType; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import com.bean.*; public class StudentFromFile { public static void main(String[] args) { File file=new File("stu.bin"); try { FileInputStream fin=new FileInputStream(file); ObjectInputStream oin=new ObjectInputStream(fin); Object obj=oin.readObject(); while (obj!=null){//读取文件中存储的所有对象 Student st= (Student) obj; System.out.println("编号:"+st.getSid()); System.out.println("姓名:"+st.getSname()); System.out.println("性别:"+st.getSex()); System.out.println("地址:"+st.getAddress()); System.out.println("年龄:"+st.getAge()); System.out.println("==========================="); oin=new ObjectInputStream(fin);//从剩余的文件输入流中继续读取数据给对象流 obj=oin.readObject(); } oin.close(); } catch (EOFException e){ System.out.println("文件已到末尾!"); }catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } |
- 存储List集合对象到文件(List集合的子类都是经过序列化的,可将此对象进行存储)
package com.test; import java.io.*; import com.bean.*; import java.util.*; public class ListToFile { public static void main(String[] args) { File file=new File("studb.bin"); List<Student> lsst=new ArrayList<>(); Student st1=new Student(1,"武松","男","景阳冈",22); Student st2=new Student(2,"潘金莲","女","景阳冈",21); Student st3=new Student(3,"西门庆","男","景阳冈",25); Student st4=new Student(4,"林冲","男","汴梁",32); Student st5=new Student(5,"鲁智深","男","济南",23); Student st6=new Student(6,"阎婆惜","女","郓城",21); lsst.add(st1); lsst.add(st2); lsst.add(st3); lsst.add(st4); lsst.add(st5); lsst.add(st6); try { FileOutputStream fout=new FileOutputStream(file); BufferedOutputStream bout=new BufferedOutputStream(fout); ObjectOutputStream objout=new ObjectOutputStream(bout); objout.writeObject(lsst);//jdk8.0可以写入 objout.flush(); objout.close(); System.out.println("保存成功!"); } catch (IOException e) { e.printStackTrace(); } } } |
反序列化List集合在程序中呈现
package com.test; import java.io.*; import com.bean.*; import java.util.*; public class ListFromFile { public static void main(String[] args) { File file=new File("studb.bin"); try { //创建文件输入流对象 FileInputStream fin=new FileInputStream(file); //创建缓冲区输入流对象 BufferedInputStream bin=new BufferedInputStream(fin); //创建对象输入流 ObjectInputStream oin=new ObjectInputStream(bin); List<Student> lsst= (List<Student>) oin.readObject(); for (Student st:lsst){ System.out.println("编号:"+st.getSid()); System.out.println("姓名:"+st.getSname()); System.out.println("性别:"+st.getSex()); System.out.println("地址:"+st.getAddress()); System.out.println("年龄:"+st.getAge()); System.out.println("==========================="); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } |
- 使用序列化和反序列化操作map集合(使用HashMap)
- 写出Map集合数据到文件
package com.test; import java.io.*; import java.util.*; import com.bean.*; public class MapToFile { public static void main(String[] args) { File file=new File("stumap.bin"); Student st1=new Student(1,"武松","男","景阳冈",22); Student st2=new Student(2,"潘金莲","女","景阳冈",21); Student st3=new Student(3,"西门庆","男","景阳冈",25); Student st4=new Student(4,"林冲","男","汴梁",32); Student st5=new Student(5,"鲁智深","男","济南",23); Student st6=new Student(6,"阎婆惜","女","郓城",21); Map<Integer,Student> map=new HashMap<>(); map.put(st1.getSid(),st1); map.put(st2.getSid(),st2); map.put(st3.getSid(),st3); map.put(st4.getSid(),st4); map.put(st5.getSid(),st5); map.put(st6.getSid(),st6); try { FileOutputStream fout=new FileOutputStream(file); BufferedOutputStream bout=new BufferedOutputStream(fout); ObjectOutputStream bs=new ObjectOutputStream(bout); bs.writeObject(map); bs.flush(); bs.close(); System.out.println("map集合写出ok!"); } catch (IOException e) { e.printStackTrace(); } } } |
- 从文件中获取Map集合的数据(反序列)
package com.test; import java.io.*; import java.util.*; import com.bean.*; public class MapToFile { public static void main(String[] args) { File file=new File("stumap.bin"); Student st1=new Student(1,"武松","男","景阳冈",22); Student st2=new Student(2,"潘金莲","女","景阳冈",21); Student st3=new Student(3,"西门庆","男","景阳冈",25); Student st4=new Student(4,"林冲","男","汴梁",32); Student st5=new Student(5,"鲁智深","男","济南",23); Student st6=new Student(6,"阎婆惜","女","郓城",21); Map<Integer,Student> map=new HashMap<>(); map.put(st1.getSid(),st1); map.put(st2.getSid(),st2); map.put(st3.getSid(),st3); map.put(st4.getSid(),st4); map.put(st5.getSid(),st5); map.put(st6.getSid(),st6); try { FileOutputStream fout=new FileOutputStream(file); BufferedOutputStream bout=new BufferedOutputStream(fout); ObjectOutputStream bs=new ObjectOutputStream(bout); bs.writeObject(map); bs.flush(); bs.close(); System.out.println("map集合写出ok!"); } catch (IOException e) { e.printStackTrace(); } } } |
反序列Map集合
package com.test; import java.io.*; import java.util.*; import com.bean.*; public class MapFromFile { public static void main(String[] args) { File file=new File("stumap.bin"); try { FileInputStream fin=new FileInputStream(file); BufferedInputStream bin=new BufferedInputStream(fin); ObjectInputStream oin=new ObjectInputStream(bin); Object obj=oin.readObject(); Map<Integer,Student> map= (Map<Integer, Student>) obj; for(Integer key:map.keySet()){//通过Map集合获取键集合Set Student st=map.get(key); System.out.println("编号:"+st.getSid()); System.out.println("姓名:"+st.getSname()); System.out.println("性别:"+st.getSex()); System.out.println("地址:"+st.getAddress()); System.out.println("年龄:"+st.getAge()); System.out.println("==========================="); }; } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } |
- 使用transient修饰符对成员属性进行非序列化处理
package com.bean; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; public class Student implements Serializable { private int sid; private String sname; private String sex; private transient String address;//此属性进行不序列化处理 private int age; public Student() { } public Student(int sid, String sname, String sex, String address, int age) { this.sid = sid; this.sname = sname; this.sex = sex; this.address = address; this.age = age; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }
} |
- 对非序列化属性进行独立序列化的处理
package com.bean; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; public class Student implements Serializable { private int sid; private String sname; private String sex; private transient String address;//此属性进行不序列化处理 private int age; public Student() { } public Student(int sid, String sname, String sex, String address, int age) { this.sid = sid; this.sname = sname; this.sex = sex; this.address = address; this.age = age; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } private void writeObject(ObjectOutputStream objectOutputStream) throws IOException{ objectOutputStream.defaultWriteObject(); System.out.println("正在对地址address序列化........"); address=address+new Date().getTime(); objectOutputStream.writeUTF(address); } private void readObject(ObjectInputStream oin) throws IOException, ClassNotFoundException { oin.defaultReadObject(); System.out.println("正在对地址address反序列化........"); address=oin.readUTF(); } } |
- 使用序列化版本在反序列化时保证对象的一致性
使用序列化版本后,类的属性发生变化,也不会影响到后续对象从文件读取反序列的操作
package com.bean; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; public class Student implements Serializable { private static final long serialVersionUID=100000000L; private int sid; private String sname; private String sex; private transient String address;//此属性进行不序列化处理 private int age; private int x=10; private int y=20; public Student() { } public Student(int sid, String sname, String sex, String address, int age) { this.sid = sid; this.sname = sname; this.sex = sex; this.address = address; this.age = age; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getAge() { return age; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public void setAge(int age) { this.age = age; } private void writeObject(ObjectOutputStream objectOutputStream) throws IOException{ objectOutputStream.defaultWriteObject(); System.out.println("正在对地址address序列化........"); address=address+new Date().getTime(); objectOutputStream.writeUTF(address); } private void readObject(ObjectInputStream oin) throws IOException, ClassNotFoundException { oin.defaultReadObject(); System.out.println("正在对地址address反序列化........"); address=oin.readUTF(); } } |
- 综合案例
- 使用集合框架、流和序列化构建员工信息管理
- 构建的步骤
- 创建员工实体类并序列化
package com.bean; import java.io.Serializable; import java.util.*; public class Empimplements Serializable{ private static final long serialVersionUID=1000000002L; private int eid; private String ename; private String sex; private String address; private String tel; private Date birthday; private String depname; private String hoby; public Emp() { } public Emp(int eid, String ename, String sex, String address, String tel, Date birthday, String depname, String hoby) { this.eid = eid; this.ename = ename; this.sex = sex; this.address = address; this.tel = tel; this.birthday = birthday; this.depname = depname; this.hoby = hoby; } public Emp(String ename, String sex, String address, String tel, Date birthday, String depname, String hoby) { this.ename = ename; this.sex = sex; this.address = address; this.tel = tel; this.birthday = birthday; this.depname = depname; this.hoby = hoby; } public int getEid() { return eid; } public void setEid(int eid) { this.eid = eid; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getDepname() { return depname; } public void setDepname(String depname) { this.depname = depname; } public String getHoby() { return hoby; } public void setHoby(String hoby) { this.hoby = hoby; } } |
- 构建工具类,向文件中写入员工集合对象,从文件中获取员工的集合信息
EmpUtil.java
package com.util; import java.io.*; import java.util.*; import com.bean.*; public class EmpUtil { private File file=null; public EmpUtil(){ file= new File("empdb.bin"); } /** * 向文件中写入员工的集合 * */ public void writeListToFile(List<Emp> lsemp){ //File file=new File("empdb.bin"); try { FileOutputStream fout=new FileOutputStream(file); BufferedOutputStream bout=new BufferedOutputStream(fout); ObjectOutputStream os=new ObjectOutputStream(bout); if(lsemp!=null&&lsemp.size()>0){ os.writeObject(lsemp); } os.flush(); os.close(); System.out.println("员工集合信息写出到文件成功!"); } catch (IOException e) { e.printStackTrace(); } } /***** * 从文件获取员工集合信息 * */ public List<Emp> readListFromFile(){ if(!file.exists()){ return null; } try { FileInputStream fin=new FileInputStream(file); BufferedInputStream bin=new BufferedInputStream(fin); ObjectInputStream oin=new ObjectInputStream(bin); List<Emp> lsemp= (List<Emp>) oin.readObject(); return lsemp; } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } } |
- 构建业务接口和实现类
EmpBiz.java
package com.biz; public interface EmpBiz<Emp> { public void save(Emp emp); public void update(Emp emp); public void delById(int eid); public void findById(int eid); public void findAll(); /** * 判断是否存在相同的编号,修改数据时使用 * */ public boolean isSid(int eid); } |
EmpBizImp.java
package com.biz; import java.text.SimpleDateFormat; import java.util.*; import com.bean.*; import java.io.*; import com.util.*; public class EmpBizImp implements EmpBiz<Emp> { private List<Emp> lsemp=null; private int eid;//员工编号 private EmpUtil empUtil=new EmpUtil();//创建自己的工具类对象准备读写文件 @Override public void save(Emp emp) { //从文件中获取员工的集合 lsemp=empUtil.readListFromFile(); /******************处理员工编号的自增***********/ if(lsemp==null||lsemp.isEmpty()){ lsemp=new ArrayList<>(); eid=1; emp.setEid(eid); }else{ List<Integer> lseid=new ArrayList<>();//用于存储员工的编号信息 for(Emp emp1:lsemp){ lseid.add(emp1.getEid()); } int maxeid=Collections.max(lseid); maxeid++;//保证编号不重复 emp.setEid(maxeid); } /**********************************************/ boolean flag=lsemp.add(emp); if(flag){ empUtil.writeListToFile(lsemp);//写集合到文件中存储 System.out.println("保存成功!"); }else{ System.out.println("保存失败!"); } } @Override public void update(Emp emp) { //从文件中获取员工的集合 lsemp=empUtil.readListFromFile(); if(lsemp==null||lsemp.isEmpty()){ System.out.println("没有员工信息存在,请先添加!"); return; } int index=-1; int i=0; /***********找编号************************/ for(Emp emp1:lsemp){ if(emp1.getEid()==emp.getEid()){//判断集合中是否存在员工 index=i; break; } i++; } /*************************************/ if(index!=-1){ lsemp.set(index,emp);//更新 empUtil.writeListToFile(lsemp);//保存更新后的集合对象到文件 System.out.println("更新成功!"); }else{ System.out.println("查无此人,更新失败!"); } } @Override public void delById(int eid) { //从文件中获取员工的集合 lsemp=empUtil.readListFromFile(); if(lsemp==null||lsemp.isEmpty()){ System.out.println("没有员工信息存在,请先添加!"); return; } int index=-1; int i=0; /***********找编号************************/ for(Emp emp1:lsemp){ if(emp1.getEid()==eid){//判断集合中是否存在员工 index=i; break; } i++; } /*************************************/ if(index!=-1){ lsemp.remove(index);//删除索引位置处的员工对象 empUtil.writeListToFile(lsemp);//存储更新后的集合对象到文件 System.out.println("更新成功!"); }else{ System.out.println("查无此人,更新失败!"); } } @Override public void findById(int eid) { //从文件中获取员工的集合 lsemp=empUtil.readListFromFile(); if(lsemp==null||lsemp.isEmpty()){ System.out.println("没有员工信息存在,请先添加!"); return; } int index=-1; int i=0; /***********找编号************************/ for(Emp emp1:lsemp){ if(emp1.getEid()==eid){//判断集合中是否存在员工 index=i; break; } i++; } /*************************************/ if(index!=-1){ System.out.println("编号\t姓名\t性别\t地址\t电话\t生日\t部门\t爱好"); System.out.println("================================================"); Emp emp=lsemp.get(index); showEmp(emp); System.out.println("================================================"); }else{ System.out.println("查无此人!"); } } @Override public void findAll() { //从文件中获取员工的集合 lsemp=empUtil.readListFromFile(); if(lsemp==null||lsemp.isEmpty()){ System.out.println("没有员工信息存在,请先添加!"); return; } System.out.println("编号\t姓名\t性别\t地址\t电话\t生日\t部门\t爱好"); System.out.println("================================================"); for(Emp emp:lsemp){ showEmp(emp); } System.out.println("================================================"); } @Override public boolean isSid(int eid) { //从文件中获取员工的集合 lsemp=empUtil.readListFromFile(); if(lsemp==null||lsemp.isEmpty()){ System.out.println("没有员工信息存在,请先添加!"); return false; } /***********找编号************************/ for(Emp emp1:lsemp){ if(emp1.getEid()==eid){//判断集合中是否存在员工 return true; } } /*************************************/ return false; } public void showEmp(Emp emp){ System.out.println( emp.getEid()+"\t"+ emp.getEname()+"\t"+ emp.getSex()+"\t"+ emp.getAddress()+"\t"+ emp.getTel()+"\t"+ new SimpleDateFormat("yyyy-MM-dd").format(emp.getBirthday())+"\t"+ emp.getDepname()+"\t"+ emp.getHoby() ); } } |
- 构建界面交互
EmpAction.java
package com.action; import com.biz.*; import com.bean.*; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; public class EmpAction { private EmpBiz ebiz=new EmpBizImp(); private Scanner input=new Scanner(System.in); /** * 录入员工信息的方法 * */ public Emp inputEmpInfo(){ Emp emp=new Emp(); System.out.println("输入姓名:"); emp.setEname(input.next()); System.out.println("输入性别:"); emp.setSex(input.next()); System.out.println("输入地址:"); emp.setAddress(input.next()); System.out.println("输入电话:"); emp.setTel(input.next()); while(true){ try { System.out.println("输入生日(1990-01-01):"); String sdate=input.next(); Date bdate=new SimpleDateFormat("yyyy-MM-dd").parse(sdate); emp.setBirthday(bdate); break; } catch (ParseException e) { System.out.println("日期格式错误!"); input=null; input=new Scanner(System.in); } } System.out.println("输入部门:"); emp.setDepname(input.next()); System.out.println("输入爱好:"); emp.setHoby(input.next()); return emp; } /** * 菜单 * */ public void showMenu(){ int eid=-1; while (true){ try { System.out.println("==员工信息管理=="); System.out.println("1--添加"); System.out.println("2--修改"); System.out.println("3--删除"); System.out.println("4--查找"); System.out.println("5--显示"); System.out.println("0--退出"); System.out.println("=============="); System.out.println("请输入选择(0-5)之间的数字:"); int op=input.nextInt(); switch (op){ case 1: System.out.println("员工信息>>添加>>"); Emp emp=inputEmpInfo(); ebiz.save(emp);//保存 break; case 2: System.out.println("员工信息>>修改>>"); System.out.println("输入员工编号:"); eid=input.nextInt(); boolean flag=ebiz.isSid(eid); if(!flag){ System.out.println("没有此编号的员工存在,请重新选择!"); break; } emp=inputEmpInfo(); emp.setEid(eid); ebiz.update(emp);//更新 break; case 3: System.out.println("员工信息>>删除>>"); System.out.println("输入员工编号:"); eid=input.nextInt(); flag=ebiz.isSid(eid); if(!flag){ System.out.println("没有此编号的员工存在,请重新选择!"); break; } ebiz.delById(eid);//删除 break; case 4: System.out.println("员工信息>>查找>>"); System.out.println("输入员工编号:"); eid=input.nextInt(); ebiz.findById(eid);//查找 break; case 5: System.out.println("员工信息>>显示>>"); ebiz.findAll(); break; case 0: System.out.println("谢谢使用,系统退出!"); System.exit(0); break; default: System.out.println("请输入0-5之间的数字!"); break; } } catch (Exception e) { System.out.println("请输入正确的选择!"); input=null; input=new Scanner(System.in); } } } } |
- 运行MainEmp.java
package com.main; import com.action.EmpAction; public class MainEmp { public static void main(String[] args) { new EmpAction().showMenu(); } } |