Java基础-IO流对象之序列化(ObjectOutputStream)与反序列化(ObjectInputStream)

                                          作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.对象的序列化与反序列化

  ObjectOutputStream流用于将对象保存在磁盘中,或者通过网络传输到另一台主机上。保存在文件中的对象的二进制流可以用ObjectInputStream流在以后被还原成原来的对象。

  对象输出流的对象可以永久的保存在磁盘上,使对象可以脱离程序而存在,此过程也称为“序列化”过程,反之,将磁盘的数据加载到内存中的就称为“反序列化”过程。换句话说,对象中的数据以流的形式写入到文件中保存的过程称为写出对象,也叫对象的序列化,在文件中以流的形式将对象读取出来,读取对象的过程也叫反序列化。

  

  注意:反序列化是不走构造方法的哟!

二.ObjectOutputStream流写对象

  类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。

  接下来我们定义一个实现Serializable类接口如下:

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ package cn.org.yinzhengjie.note6; import java.io.Serializable; public class Person implements Serializable{
private String Name;
private int Age;
public Person(String name, int age) {
super();
Name = name;
Age = age;
} public String getName() {
return Name;
} public void setName(String name) {
Name = name;
} public int getAge() {
return Age;
} public void setAge(int age) {
Age = age;
} @Override
public String toString() {
return "Person [姓名=" + Name + ",年龄=" + Age+ "]";
}
}

Person.java 文件内容

  定义好需要序列化的对象之后,我们需要就来搞事情吧,看看ObjectOutputStream 到底是如何使用的,案例如下:

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ package cn.org.yinzhengjie.note6; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream; public class ObjectOutputStreamDemo {
public static void main(String[] args) throws IOException {
//创建字节输出流,封装文件
File file = new File("yinzhengjie.txt");
if(!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file); //创建写出对象的序列化流的对象,构造方法传递字节输出流
ObjectOutputStream oos = new ObjectOutputStream(fos);
Person p = new Person("yinzhengjie", 18);
//调用序列化流的方法writeObject,写出对象。需要实例对象p具有序列化接口,否则会抛出异常对象:java.io.NotSerializableException
oos.writeObject(p);
//别忘了释放资源哟!
oos.close();
}
}

三.ObjectInputStream流读取对象

  在反序列一个文件内容的时候可能会存在java.lang.ClassNotFoundException类异常,原因是缺少反序列的字节码(*.class)文件。因此,序列化的前提是:必须有反序列化相关的字节码文件。现在我们把之前序列化的文件进行反序列操作,如下:

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ package cn.org.yinzhengjie.note6; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream; public class ObjectInputSteamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建字节输入流,封装文件
File file = new File("yinzhengjie.txt");
FileInputStream fis = new FileInputStream(file);
//创建反序列化流,构造方法中,传递字节输入流
ObjectInputStream ois = new ObjectInputStream(fis);
//调用反序列化流的方法"readObject()"读取对象,要注意的是反序列话的对象需要存在相应的字节码文件。否则会抛异常
Object obj = ois.readObject();
//记得释放资源
ois.close();
//查看我们的想要看的内容。
System.out.println(obj);
}
} /*
以上代码执行结果如下:
Person [姓名=yinzhengjie,年龄=18]
*/

  注意,在序列化和反序列化过程中,序列化用的什么方法写入,我们读取的时候也应该用对应的方法去读取,打个比方,我们上面序列化一个自定义类时,用的是wirteObject()方法,读取的时候应该用对应方法读取,我们上面的案例就是用readObject方法进行读取,如果你序列化使用的wirteInt()方法,那么反序列话的时候就应该用readInt()方法哟!谨记这一点,会让你少踩很多坑的,别问我为什么这么说,因为这个坑我已经踩了你就别去踩了哈!

四.关于序列化的面试题

1>.静态成员变量为什么不能被序列化?

  答:序列化其实是将对象进行序列化操作,而static修饰的成员变量是属于类的,并非对象所有!因此静态修饰的成员变量无法被序列化。

2>.瞬态关键字transient的用法?

  答:当一个类的对象需要被序列化时,某些属性不需要被反序列化,这时不需要序列化的属性可以使用关键字transient修饰,只要被transient修饰了,序列化时这个属性就不会被序列化啦!它的用法比较单一,只能用于修饰成员变量不被序列化!这样做的目的是可以节省空间,将不需要的数据不进行序列化操作。

3>.Serializable接口有上面含义?

  答:Serializable并没有任何功能,只是一个标记性接口,就好像去菜市场买猪肉,安检人员会在猪肉上印上一个标记表示该猪肉检验合格可以食用!而在Java中用该接口只是标识该类是可以被序列化!

4>.分析序列化中的为什么会存在序列化冲突问题?

  答:Java代码在执行之前需要经过javac命令对源代码进行编译生成字节码文件“*.class”,与此同时会给该“*.class”计算出来一个序列号(serialVersionUID),在序列化时会将该属性一并序列化到文件中。当我们对源代码再次进行编辑时,依然是需要javac命令进行编译该文件才能运行修改后的代码,此时会生成一个新的序列号(serialVersionUID)出来。这个时候当我们将序列化的文件进行反序列化操作时,首先会对比字节码文件的序列号是否一致,如果不一致,则会抛出异常:“java.io.InvalidClassException”。

5>.为什么要自定义序列号?

  答:原因很简单,就是为了解决序列化冲突问题。我们只需要要让源代码修改前和修改后的序列号(serialVersionUID)保持一致,这样就可以正常进行序列化操作啦!我们可以看一下案例如下:

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ package cn.org.yinzhengjie.note6; import java.io.Serializable; public class Person implements Serializable{
private String Name;
public /*transient关键字在这里加,就可以阻止成员变量进行序列化啦!*/int Age; static final long serialVersionUid = 7758520L; //类自定义序列号,编译器就不会计算序列号。 public Person(String name, int age) {
super();
Name = name;
Age = age;
} public String getName() {
return Name;
} public void setName(String name) {
Name = name;
} public int getAge() {
return Age;
} public void setAge(int age) {
Age = age;
} @Override
public String toString() {
return "Person [姓名=" + Name + ",年龄=" + Age+ "]";
} }

五.小试牛刀

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; /**
* 客户类
*/
public class Customer implements Serializable {
private static final long serialVersionUID = 6327665722505706622L;
private String name ;
private int age ; public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} //临时的,不参与串行化
private transient List<Order> orders = new ArrayList<Order>() ; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public List<Order> getOrders() {
return orders;
} public void setOrders(List<Order> orders) {
this.orders = orders;
}
}

Customer.java 文件内容

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.serializable; import java.io.Serializable; /**
* 客户类
*/
public class Item implements Serializable {
private String itemname; public String getItemname() {
return itemname;
} public void setItemname(String itemname) {
this.itemname = itemname;
}
}

Item.java 文件内容

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; /**
* 客户类
*/
public class Order implements Serializable {
private String orderno; private List<Item> items =new ArrayList<Item>() ; public List<Item> getItems() {
return items;
} public void setItems(List<Item> items) {
this.items = items;
} public String getOrderno() {
return orderno;
} public void setOrderno(String orderno) {
this.orderno = orderno;
}
}

Order.java 文件内容

1>.实现浅拷贝

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.serializable; import org.junit.Test; public class ShallowReplicas {
@Test
public void testDeeplyCopy() throws Exception {
Customer c = new Customer();
c.setName("尹正杰"); Order o1 = new Order();
o1.setOrderno("0001"); Order o2 = new Order();
o2.setOrderno("0002"); Item i1 = new Item();
i1.setItemname("iphone 8 Plus"); //建立关系
c.getOrders().add(o1);
c.getOrders().add(o2); o1.getItems().add(i1); //浅度复制
Customer cc = new Customer();
cc.setName(c.getName());
cc.setOrders(c.getOrders()); String name = cc.getName();
System.out.println(name);
}
}

2>.实现深度拷贝

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ package cn.org.yinzhengjie.serializable; import org.junit.Test; import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; public class DeepCopy {
String filePath = "D:\\BigData\\JavaSE\\yinzhengjieData\\c.dat"; /**
* 深度拷贝,将对象序列化到文件
*/
@Test
public void testDeeplyCopy() throws Exception {
Customer c = new Customer();
c.setName("尹正杰"); Order o1 = new Order();
o1.setOrderno("0001"); Order o2 = new Order();
o2.setOrderno("0002"); Item i1 = new Item();
i1.setItemname("iphone 8 Plus"); //建立关系
c.getOrders().add(o1);
c.getOrders().add(o2); o1.getItems().add(i1); //深度拷贝,将对象序列化到文件
FileOutputStream fos = new FileOutputStream(filePath) ;
ObjectOutputStream oos = new ObjectOutputStream(fos) ;
oos.writeObject(c);
oos.close();
fos.close();
System.out.println();
} /**
* 定义反序列化的代码
*/
@Test
public void testDeserialize() throws Exception {
FileInputStream fis = new FileInputStream(filePath);
ObjectInputStream ois = new ObjectInputStream(fis);
Customer obj = (Customer)ois.readObject();
ois.close();
fis.close();
System.out.println(obj.getName());
}
} /*
以上代码执行结果如下:
尹正杰
*/

Java基础-IO流对象之序列化(ObjectOutputStream)与反序列化(ObjectInputStream)的更多相关文章

  1. Java基础-IO流对象之压缩流(ZipOutputStream)与解压缩流(ZipInputStream)

    Java基础-IO流对象之压缩流(ZipOutputStream)与解压缩流(ZipInputStream) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 之前我已经分享过很多的J ...

  2. Java基础-IO流对象之随机访问文件(RandomAccessFile)

    Java基础-IO流对象之随机访问文件(RandomAccessFile) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.RandomAccessFile简介 此类的实例支持对 ...

  3. Java基础-IO流对象之内存操作流(ByteArrayOutputStream与ByteArrayInputStream)

    Java基础-IO流对象之内存操作流(ByteArrayOutputStream与ByteArrayInputStream) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.内存 ...

  4. Java基础-IO流对象之数据流(DataOutputStream与DataInputStream)

    Java基础-IO流对象之数据流(DataOutputStream与DataInputStream) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.数据流特点 操作基本数据类型 ...

  5. Java基础-IO流对象之打印流(PrintStream与PrintWriter)

    Java基础-IO流对象之打印流(PrintStream与PrintWriter) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.打印流的特性 打印对象有两个,即字节打印流(P ...

  6. java基础-IO流对象之Properties集合

    java基础-IO流对象之Properties集合 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Properties集合的特点 Properties类表示了一个持久的属性集. ...

  7. Java基础-IO流对象之字符缓冲流(BufferedWriter与BufferedReader)

    Java基础-IO流对象之字符缓冲流(BufferedWriter与BufferedReader) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.字符缓冲流 字符缓冲流根据流的 ...

  8. Java基础-IO流对象之字节缓冲流(BufferedOutputStream与BufferedInputStream)

    Java基础-IO流对象之字节缓冲流(BufferedOutputStream与BufferedInputStream) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在我们学习字 ...

  9. Java基础-IO流对象之转换流(InputStreamReader与OutoutStreamWriter)

    Java基础-IO流对象之转换流(InputStreamReader与OutoutStreamWriter) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.转换流概述 我们之前 ...

随机推荐

  1. Java第二次实验20135204

    一.实验过程: 1.先创建一个学号命名的文档: 2.一个百分制成绩转化为等级: 3.新建一个包,另一个测试: 4.打开UML,建模软件umbrello进行建模: 相关程序: 5.我的保存: 二.遇到的 ...

  2. beta冲刺(7/7)

    目录 组员情况 组员1:胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:恺琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:何宇恒 组员11:刘一好 展示组内最新 ...

  3. Unity3D游戏开发——编程实现游戏管理器

    本篇简介 本篇介绍了如何将上一篇的设计模式思想运用到实际的开发过程中. 脚本文件 (1)IGameManager:这个接口存在声明了一个属性(一个拥有getter函数的变量,属性的类型是Manager ...

  4. 19_集合_第19天(List、Set)_讲义

    今日内容介绍 1.List接口 2.Set接口 3.判断集合唯一性原理 非常重要的关系图 xmind下载地址 链接:https://pan.baidu.com/s/1kx0XabmT27pt4Ll9A ...

  5. vue 中ref 的使用注意事项

    最近看别人的项目发现有些语法不能理解,所以百度进行了学习.现在总结一下. ref 有两种用法 1.ref 加在普通的元素上,用this.ref.name 获取到的是dom元素 2.ref 加在子组件上 ...

  6. 对一致性Hash算法及java实现(转)

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  7. m3u8 player

    m3u8 player m3u8 是一种基于 HTTP Live Streaming 文件视频格式,它主要是存放整个视频的基本信息和分片(Segment)组成.目前 由 Apple.inc 率先提出的 ...

  8. js本地储存userData实例

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...

  9. 【刷题】BZOJ 4817 [Sdoi2017]树点涂色

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  10. 【BZOJ1048】分割矩阵(记忆化搜索,动态规划)

    [BZOJ1048]分割矩阵(记忆化搜索,动态规划) 题面 BZOJ 洛谷 题解 一个很简单的\(dp\),写成记忆化搜索的形式的挺不错的. #include<iostream> #inc ...