zoukankan      html  css  js  c++  java
  • Java基础(八)——IO流3_对象流 Craftsman

    一、对象流

    1、序列化与反序列化

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

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

    2、ObjectOutputStream、ObjectInputStream

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

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

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

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

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

    作者:Craftsman-L

    本博客所有文章仅用于学习、研究和交流目的,版权归作者所有,欢迎非商业性质转载。

    如果本篇博客给您带来帮助,请作者喝杯咖啡吧!点击下面打赏,您的支持是我最大的动力!

  • 相关阅读:
    vscode插件推荐
    Node.js连接mysql
    vscode设置语言
    sql查询某字段的相同值
    CORS跨域请求C#版
    NPOI之C#下载Excel
    Linux常用命令记录
    C#汉字转拼音
    C#读写txt文件
    linux修改文件权限命令(chmod)
  • 原文地址:https://www.cnblogs.com/originator/p/15762424.html
Copyright © 2011-2022 走看看