一、对象流

1、序列化与反序列化

  序列化:将内存中的Java对象保存到磁盘中或通过网络传输出去。
  反序列化:将磁盘文件中的对象还原为内存中的一个Java对象。

  用途:
  (1)将对象保存到物理硬盘:比如Web服务器中的Session对象,当有10万用户并发访问时,有可能出现10万个Session对象,内存可能吃不消,从而导致OOM。于是Web容器就会把一些Session序列化到硬盘中,等需要时,再把硬盘中的对象反序列化到内存中。
  (2)将对象在网络上进行传输:当两个进程进行通信时,数据都会以二进制序列的形式在网络上进行传输。发送方需要把这个Java对象转换为字节序列,才能在网络上传输;接收方则需要把字节序列再恢复为Java对象。

2、ObjectOutputStream、ObjectInputStream

  字节流,处理流。ObjectOutputStream 和 ObjectInputStream,用于存储和读取基本数据类型或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
  序列化:用ObjectOutputStream类保存基本类型数据或对象的机制。
  反序列化:用ObjectInputStream类读取基本类型数据或对象的机制。
  注:不能序列化static和transient修饰的成员变量。

  如何进行序列化?
  (1)必须实现接口:Serializable,这是一个标识接口,没有任何抽象方法,用于表明该类是可序列化的。
  (2)定义一个全局常量:serialVersionUID,这个常量是可选的,用于标识类的版本号。
  (3)若类有类属性:必须保证该类的所有属性也是可序列化的。
  代码示例:标准模板

  1. 1 public class Person implements Serializable {
  2. 2 private static final long serialVersionUID = 1L;
  3. 3 }

  代码示例:序列化与反序列化

  1. 1 // 序列化.对象->磁盘
  2. 2 public class Main {
  3. 3 public static void main(String[] args) {
  4. 4 try (FileOutputStream stream = new FileOutputStream("Obj.dat");
  5. 5 // 对象输出流
  6. 6 ObjectOutputStream oos = new ObjectOutputStream(stream);) {
  7. 7
  8. 8 oos.writeObject("用于测试序列化");
  9. 9 oos.writeObject(new Person(1001, "张三", new Account(11.1)));
  10. 10 } catch (Exception e) {
  11. 11 }
  12. 12 }
  13. 13 }
  14. 14
  15. 15 // 反序列化.磁盘->对象
  16. 16 public class Main {
  17. 17 public static void main(String[] args) {
  18. 18 try (FileInputStream stream = new FileInputStream("Obj.dat");
  19. 19 // 对象输入流
  20. 20 ObjectInputStream ois = new ObjectInputStream(stream);) {
  21. 21
  22. 22 String str = (String) ois.readObject();
  23. 23 Person p = (Person) ois.readObject();
  24. 24
  25. 25 System.out.println(str);
  26. 26 System.out.println(p);
  27. 27 } catch (Exception e) {
  28. 28 }
  29. 29 }
  30. 30 }
  31. 31
  32. 32
  33. 33 class Person implements Serializable {
  34. 34 public static final long serialVersionUID = 1L;
  35. 35 private int id;
  36. 36 private String name;
  37. 37 // private transient double hight; // 不需要序列化
  38. 38 private Account acct; // acct属性必须也是可序列化的
  39. 39
  40. 40 // 无参构造器
  41. 41 // 有参构造器
  42. 42 // getter & setter
  43. 43 // toString()
  44. 44 }
  45. 45
  46. 46 class Account implements Serializable {
  47. 47 public static final long serialVersionUID = 1L;
  48. 48 private double balance;
  49. 49
  50. 50 // 无参构造器
  51. 51 // 有参构造器
  52. 52 // getter & setter
  53. 53 // toString()
  54. 54 }

  总结(重要):
  (1)若未实现接口Serializable,会直接报java.io.NotSerializableException异常。
  (2)实现Serializable,但不写serialVersionUID,不会有异常,但是会有隐藏的问题。如果类已经序列化了,此时修改了类的结构,比如新增了一个属性,再反序列化的时候会报错。
  (3)如果类中某个属性不想被序列化,可以加上关键字transient。

3、serialVersionUID的理解

  若没有

  private static final long serialVersionUID = 1L;

  先序列化类,然后修改类的结构(如,新增一个字段),再反序列化。会报错如下:

  java.io.InvalidClassException: temp.file.Person; local class incompatible: stream classdesc serialVersionUID = 503624515100475858, local class serialVersionUID = -443494311322032311

  serialVersionUID:序​列​化​的​版​本​号​,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量,用来表明类的不同版本间的兼容性。
如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的结构做了修改,文件流中的class和classpath中的class不兼容了,处于安全机制考虑,程序抛出异常,并拒绝载入。
  解决:上述问题只需要显式声明 serialVersionUID 即可。
  既然 serialVersionUID 是在序列化的时候使用到,那么抽象类(abstract)没有实例被序列化是不是就不需要定义 serialVersionUID 属性呢?事实是序列化的时候会递归获取父类的描述,所以如果父类的 serialVersionUID 修改了,同样会导致子类对象反序列化失败。

Java基础(八)——IO流3_对象流的更多相关文章

  1. java基础之IO流(二)之字符流

    java基础之IO流(二)之字符流 字符流,顾名思义,它是以字符为数据处理单元的流对象,那么字符流和字节流之间的关系又是如何呢? 字符流可以理解为是字节流+字符编码集额一种封装与抽象,专门设计用来读写 ...

  2. java基础之IO流(一)字节流

    java基础之IO流(一)之字节流 IO流体系太大,涉及到的各种流对象,我觉得很有必要总结一下. 那什么是IO流,IO代表Input.Output,而流就是原始数据源与目标媒介的数据传输的一种抽象.典 ...

  3. Java基础之IO流整理

    Java基础之IO流 Java IO流使用装饰器设计模式,因此如果不能理清其中的关系的话很容易把各种流搞混,此文将简单的几个流进行梳理,后序遇见新的流会继续更新(本文下方还附有xmind文件链接) 抽 ...

  4. Java基础八--构造函数

    Java基础八--构造函数 一.子父类中构造函数的特点 1.1 为什么在子类构造对象时,发现,访问子类构造函数时,父类也运行了呢? 原因是:在子类的构造函数中第一行有一个默认的隐式语句. super( ...

  5. Java基础IO类之对象流与序列化

    对象流的两个类: ObjectOutputStream:将Java对象的基本数据类型和图形写入OutputStream ObjectInputStream:对以前使用ObjectOutputStrea ...

  6. 【java基础】]IO流

    IO流 概念: 流的概念源于unix中管道(pipe)的概念,在unix中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备,外部文件等 一个流,一定能够会有源和去向(目的地),他 ...

  7. java基础06 IO流

    IO用于在设备间进行数据传输的操作. Java IO流类图结构:   IO流分类 字节流: InputStream FileInputStream BufferedInputStream Output ...

  8. java基础之io流总结一:io流概述

    IO流概念: 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.io流是实现输入和输出的基础,可以方便的实现数据的输入和输出操作. IO流的分类: 根据处理数据类型的不同分为:字符流 ...

  9. Java基础学习总结(13)——流IO

    一.JAVA流式输入/输出原理 流是用来读写数据的,java有一个类叫File,它封装的是文件的文件名,只是内存里面的一个对象,真正的文件是在硬盘上的一块空间,在这个文件里面存放着各种各样的数据,我们 ...

随机推荐

  1. ython学习笔记(接口自动化框架 V2.0)

    这个是根据上次框架版本进行的优化 用python获取excel文件中测试用例数据 通过requets测试接口.并使用正则表达式验证响应信息内容 生成xml文件测试报告 版本更新内容: 1. 整理了Cr ...

  2. oracle keep

    语法: min | max(column1) keep (dense_rank first | last order by column2) over (partion by column3); -- ...

  3. Win10 Chrome 在DPI缩放下导致界面放大问题 解决方案

    支持:54.0.2840.59 m (64-bit) 以下大多数版本,具体未测试.如有问题可以反馈一下. 方法1:为程序设置"高DPI设置时禁用显示缩放. 方法2:为程序添加启动参数: /h ...

  4. Mybatis读取数据实战

    1.Mybatis基础配置 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configu ...

  5. python安装imblearn(PackageNotFoundError: ''Package missing in current channels")

    1.imblearn包在anaconda中是没有的,需要在命令行下自行安装,以下两个命令任选一个: 1. conda install -c glemaitre imbalanced-learn2. p ...

  6. shell脚本 阿里云基线检查一键配置

    一.简介 源码地址 日期:2017/9/1 介绍:安全加固脚本,会符合阿里云基线检查.有幂等性,可重复执行 效果图: 二.使用 适用:centos6/7 语言:中文 注意:脚本是符合阿里云基线检查的配 ...

  7. KubeCon 2021|使用 eBPF 代替 iptables 优化服务网格数据面性能

    作者 刘旭,腾讯云高级工程师,专注容器云原生领域,有多年大规模 Kubernetes 集群管理及微服务治理经验,现负责腾讯云服务网格 TCM 数据面产品架构设计和研发工作. 引言 目前以 Istio[ ...

  8. Spring框架源码干货分享之三级缓存和父子工厂

    记录并分享一下本人学习spring源码的过程,有什么问题或者补充会持续更新.欢迎大家指正! 环境: spring5.X + idea 建议:学习过程中要开着源码一步一步过 Spring中对象的创建宏观 ...

  9. SpringCloud微服务实战——搭建企业级开发框架(三十四):SpringCloud + Docker + k8s实现微服务集群打包部署-Maven打包配置

      SpringCloud微服务包含多个SpringBoot可运行的应用程序,在单应用程序下,版本发布时的打包部署还相对简单,当有多个应用程序的微服务发布部署时,原先的单应用程序部署方式就会显得复杂且 ...

  10. 存储技术之ceph了解

    ceph rados:可靠的.自动的.分布式.对象存储 特性:高效性,统一性(文件存储,块存储,对象存储),可扩展 没有数据库的概念:为cluster map 记录集群状态. PG:(ceph核心单位 ...