• 因为编辑文章时不小心用了回退键,可能导致代码出错,请自行查错

  • 1 Java序列化的作用
    • 我们创建一个Building.class
        • 
          
          public class Building {
          
            private String name;
            private String address;
          
            public String getName() {
              return name;
            }
          
            public void setName(String name) {
              this.name = name;
            }
          
            public String getAddress() {
              return address;
            }
          
            public void setAddress(String address) {
              this.address = address;
            }
          }

    • 如果需要传输对象
      •  public static void main(String[] args) {
            Building b = new Building();
            b.setName("创业大厦");
            b.setAddress("天宁兰陵兰陵路26号");
            System.out.println(b);
          }
    • 我们可以看到,传输的仅仅是类名
      • test.j3.c2.Building@2503dbd3
    • 这时,我们就需要对Building进行序列化
    • 序列化:把对象转换为字节序列的过程称为对象的序列化
    • 序列化是将对象的数据和信息转换为可以存储或传输的形式过程,需要序列化的情况为:
      • 当内存中的对象需要保存到一个文件中、数据库、缓存中的时候;
      • 当对象需要传输的时候
    • String类支持序列化
  • 2 序列化
    • 对象实现了Serializable接口,就表示可以被序列化
    • 该接口知识一个标记接口,也叫空接口,没有任何方法,所以实现了接口也不需要实现方法
    • Building.java
      • 
        
        import java.io.Serializable;
        
        public class Building implements Serializable {
          // 自定义serialVersionUID
          private static final long serialVersionUID = 8735132092273200831L;
        
          private String name;
          private String address;
        
          public String getName() {
            return name;
          }
        
          public void setName(String name) {
            this.name = name;
          }
        
          public String getAddress() {
            return address;
          }
        
          public void setAddress(String address) {
            this.address = address;
          }
        }

    • Building.java中有一个serialVersionUID
      • serialVersionUID主要是序列化和反序列化过程中,验证类的版本用的
      • 例如:
        • Building类有两个属性:name、address,如果先把Building对象序列化,然后修改Building类,再反序列化就会失败
        • 为了避免这种情况,给serialVersionUIF赋一个固定的值,那么无论Building类增加几个属性,都能正确反序列化
    • 自动生成serialVersionUID
      • IDE工具可以方便的提供自动生成serialVersionUID值的功能
      • 以IntelliJ IDEA为例:
        1. Setting->Inspections ->Serialization issues -> Serializable class without 'serialVersionUID'
          • 图片
        2. 点击”OK”后,打开代码。鼠标指到类名上
          • 图片
        3. 点开黄色灯泡提示按钮的小箭头,选择ADD ‘serialVersionUID’ field
          • 图片
    • JSON
      • JSON: javaScipt Object Notation(JavaScript对象表示法)是目前最常用的对象序列化方式
      • JSON官方制定了一套标准,各种语言都支持这一套标砖,所以JSON也能作为一种跨语言的文本数据交换格式,无障碍地把数据传递到其它语言的程序
      • JSON基本格式
        • 必须是:对象
          • {
            }
        • 或:数组
          • [
            ]
      • JSON语法规则
        • 数据用 名称:值(也叫键值对〕表示
          • 名称(键)必须是字符串
          • 键、值之间用冒号”:”分隔。
        •  多条数据之间,用逗号”,”分隔
        • 符号都是半角
      •   JSON值的类型
        • 数字(整数或浮点数)
        • 字符串(在双引号中)
        • 逻辑值(true或false)
        • 数组(在中括号中)
        • 对象(在大括号中)
        • null
        • 值可以是数组、对象,就意味着数据和对象可以任意嵌套、任意深度
      • eg:
        • {
              "name": "韦小宝",
              "age": 26,
              "height": 182.4,
              "birthday": "1670-7-28",
              "isRich": true,
              "wifes": ["阿珂", "双儿", "建宁公主", "苏荃", "沐剑屏", "曾柔", "方怡"],
              "firstMaster": {
                "name": "陈近南",
                "birthday": "1634-12-1"
              }
          }
    • FastJSON
      • FastJSON是一个Java语言编写的高性能、功能完善、完全支持官方标注你的JSON库
      • 使用其来操作JSON以及完成对象序列化、反序列化的操作,会非常方便
    • 对象序列化
      • IDE中的设置
        • 首先导入阿里的FaseJSON包
        • 然后引入依赖
          • <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.59</version>
            </dependency>
        • 最后在使用时导入
          • import com.alibaba.fastjson.JSON;
      • 用FastJson打印对象
        •  public static void main(String[] args) {
              Building b = new Building();
              b.setName("创业大厦");
              b.setAddress("天宁兰陵兰陵路26号 ");
              String content = JSON.toJSONString(b);
              System.out.println(content);
            }
    • 练习
      • 使用序列化,在console上打印”研究生公寓’,位于”杭州市江干区学林
        街628号,有’54″间房间,建筑面积”380平米”的公寓的完整信息
      • 参考类图
        • alt 参考类图
      • 代码
        • Apartment.java
        • 
          
          import java.io.Serializable;
          
          public class Apartment extends Building implements Serializable {
              private int totalRooms;
              private String builtupArea;
          
              public int getTotalRooms() {
                  return totalRooms;
              }
          
              public void setTotalRooms(int totalRooms) {
                  this.totalRooms = totalRooms;
              }
          
              public String getBuiltupArea() {
                  return builtupArea;
              }
          
              public void setBuiltupArea(String builtupArea) {
                  this.builtupArea = builtupArea;
              }
          }

        • Building.java
        • 
          
          import java.io.Serializable;
          
          public class Building  {
          
          
              private String name;
              private String address;
          
              public String getName() {
                  return name;
              }
          
              public void setName(String name) {
                  this.name = name;
              }
          
              public String getAddress() {
                  return address;
              }
          
              public void setAddress(String address) {
                  this.address = address;
              }
          }

        • ObjectPrinter.java
        • 
          
          import com.alibaba.fastjson.JSON;
          
          public class ObjectPrinter {
          
             public static void main(String[] args) {
                  Apartment apartment = new Apartment();
                  apartment.setName("研究生公寓");
                  apartment.setAddress("杭州市江干区学林街628号");
                  apartment.setTotalRooms(54);
                  apartment.setBuiltupArea("380平米");
                  String content = JSON.toJSONString(apartment);
                  System.out.println(content);
              }
          }
          

  • 3 反序列化
    • 把字节序列恢复为对象的过程称为对象的反序列化
    • 在具体案例中,就是将JSON格式字符串还原为对象的过程
    • 反序列化代码示例
      • public static void main(String[] args) {
            Building b = new Building();
            b.setName("创业大厦");
            b.setAddress("天宁兰陵兰陵路26号 ");
        
            String content = JSON.toJSONString(b);
        
            // 转换为一个具体的对象
            Building b2 = JSON.parseObject(content, Building.class);
            String name = b2.getName();
            System.out.println(name);
        
            // 特殊情况下,java系统里没有具体对象的 class ,可以反序列化为 Map
            Map bInfo = JSON.parseObject(content, Map.class);
            String name2 = (String) bInfo.get("name");
            System.out.println(name2);
          }
    • 转化为一般对象
      • 反序列化时,调用
        • JSON.parseObject(content, Building.class)
        • 第一个参数是字符串内容,第二个参数是目标类
      •  转换为具体的对象后,就可以使用对象的属性和方法了
    • 转化为Map
      •  少数复杂的场景,程序需要把字符串转换为对象,但是系统中又没有依赖具体的目标,这时可以把字符串转换为Map对象,用get(“关键字”)的方法获取对象的具体属性
    • 练习
      • 使用序列化,在console上打印”研究生公寓’,位于”杭州市江干区学林
        街628号,有’54″间房间,建筑面积”380平米”的公寓的完整信息
      • 然后再反序列化为两种对象
        • 反序列化为“公寓”对象,在console打印公寓的名称
        • 反序列化为“Map”对象,在console打印公寓的名称
      • 参考类图
        • alt 参考类图
      • 代码
        • Apartment.java
        • 
          
          import java.io.Serializable;
          
          public class Apartment extends Building implements Serializable {
              private int totalRooms;
              private String builtupArea;
          
              public int getTotalRooms() {
                  return totalRooms;
              }
          
              public void setTotalRooms(int totalRooms) {
                  this.totalRooms = totalRooms;
              }
          
              public String getBuiltupArea() {
                  return builtupArea;
              }
          
              public void setBuiltupArea(String builtupArea) {
                  this.builtupArea = builtupArea;
              }
          }

        • Building.java
        • 
          
          package com.youkeda.test.j3.c2;
          
          import java.io.Serializable;
          
          public class Building  {
          
          
              private String name;
              private String address;
          
              public String getName() {
                  return name;
              }
          
              public void setName(String name) {
                  this.name = name;
              }
          
              public String getAddress() {
                  return address;
              }
          
              public void setAddress(String address) {
                  this.address = address;
              }
          }
          

        • ObjectAssembler.java
        • 
          
          package com.youkeda.test.j3.c2;
          
          import java.util.*;
          import com.alibaba.fastjson.JSON;
          
          public class ObjectAssembler{
          
             public static void main(String[] args) {
                  Apartment apartment = new Apartment();
                  apartment.setName("研究生公寓");
                  apartment.setAddress("杭州市江干区学林街628号");
                  apartment.setTotalRooms(54);
                  apartment.setBuiltupArea("380平米");
                  String content = JSON.toJSONString(apartment);
                  System.out.println(content);
                  
                  Apartment b2 = JSON.parseObject(content, Apartment.class);
                  String name = b2.getName();
                  System.out.println(name);
          
                   // 特殊情况下,java系统里没有具体对象的 class ,可以反序列化为 Map
                  Map bInfo = JSON.parseObject(content, Map.class);
                  String name2 = (String) bInfo.get("name");
                  System.out.println(name2);
              }
          }
          

  • 4 序列化的例外情形
    • 不想类的某些属性被序列化时,需要在序列化过程中排除某些字段
    • Building.java
      • 
        
        import com.alibaba.fastjson.annotation.JSONField;
        import java.io.Serializable;
        
        public class Building implements Serializable {
          // 自定义serialVersionUID
          private static final long serialVersionUID = 8735132092273200831L;
        
          private transient String name;
        
          @JSONField(serialize=false)
          private String address;
        
          public String getName() {
            return name;
          }
        
          public void setName(String name) {
            this.name = name;
          }
        
          public String getAddress() {
            return address;
          }
        
          public void setAddress(String address) {
            this.address = address;
          }
        }

    • 常用排除字段的方式有两种
      • 在字段上增加一个@JSONField(serialize=false) 注解,这个注解是 fastjson库提供的
      • 在声明字段时,增加一个 transient 修饰关键字,这个关键字是 JDK 本身提供的
    •  对于一个属性,这两种方法任选其一,在执行序列化的时候,都可以实现忽略其值
    • 需要特别注意的是:这两种方式只对“序列化”过程有效,对“反序列化”过程无效
    • 反序列化时,不受影响,只要 JSON 字符串有内容,都会按规则反序列化为对象并为属性赋值,不会因为属性字段标记为排除而不赋值
    • 练习
      • 使用序列化,在console上打印”研究生公寓’,位于”杭州市江干区学林
        街628号,有’54″间房间,建筑面积”380平米”的公寓的完整信息
      • 然后再反序列化为两种对象
        • 公寓的“建筑面积”、“地址”两个属性设置为不可序列化
        • 反序列化为“公寓”对象,在console打印公寓的名称
        • 反序列化为“Map”对象,在console打印公寓的名称
      • 参考类图
        • alt 参考类图
      • 代码
        • Apartment.java
        • 
          
          import java.io.Serializable;
          
          public class Apartment extends Building implements Serializable {
              private int totalRooms;
              private  transient String builtupArea;
          
              public int getTotalRooms() {
                  return totalRooms;
              }
          
              public void setTotalRooms(int totalRooms) {
                  this.totalRooms = totalRooms;
              }
          
              public String getBuiltupArea() {
                  return builtupArea;
              }
          
              public void setBuiltupArea(String builtupArea) {
                  this.builtupArea = builtupArea;
              }
          }

        • Building.java
        • 
          
          package com.youkeda.test.j3.c2;
          
          import com.alibaba.fastjson.annotation.JSONField;
          import java.io.Serializable;
          
          public class Building  {
          
          
              private String name;
          
             @JSONField(serialize=false)
              private String address;
          
              public String getName() {
                  return name;
              }
          
              public void setName(String name) {
                  this.name = name;
              }
          
              public String getAddress() {
                  return address;
              }
          
              public void setAddress(String address) {
                  this.address = address;
              }
          }
          

        • ObjectAssembler2.java
        • 
          
          package com.youkeda.test.j3.c2;
          
          import com.alibaba.fastjson.JSON;
          
          import java.util.Map;
          
          public class ObjectAssembler2 {
          
              public static void main(String[] args) {
                  Apartment apartment = new Apartment();
                  apartment.setName("研究生公寓");
                  apartment.setAddress("杭州市江干区学林街628号");
                  apartment.setTotalRooms(54);
                  apartment.setBuiltupArea("380平米");
                  String content = JSON.toJSONString(apartment);
                  System.out.println("Apartment2 对象="+content);
          
                  Apartment b2 = JSON.parseObject(content, Apartment.class);
                  System.out.println("Apartment2 对象建筑面积="+b2.getBuiltupArea());
          
                  // 特殊情况下,java系统里没有具体对象的 class ,可以反序列化为 Map
                  Map bInfo = JSON.parseObject(content, Map.class);
                  System.out.println("Map.address 值=" + (String) bInfo.get("address"));
              }
          }

  • 5 持久化
    • 对象经过处理,冉存储在介质上的过程,就叫做持久化(Persistence)
    • 持久化包含对象的存储和读取两个过程
    • 实际上,由于对象是存储在计算机的内存中,是临时性的,所以必须有一种方式,能够存储下来,不随着程序停止运行或计算机关机等异常况而丢失
    • 常见的久化方式有
      • 写入数据库
        • 对象写入数据,一般来说数据库都有对应的字段,使用Mybatis等框架完成读写数据,这种信况一般不需要使用序列化。但是对于一些不会检索、需要有扩展性的字段来说,可以在数据库表结构的对应字段中,存储巧JSON格式的字符串,在Java程序中再次反序列化成一个对象,使用方便且具备扩展性
      •  写入远程的缓存系统
        • 这种信况下通用的方法,就是把对象序列化为JSON字符,存入缓存。使用起来方便而简单
      •  写入文件
        • 在云时代,这种情况不太多见了,偶尔有会有,把对象序列化为JSON字符串写入文件。需要的时候再读取文件内容反序列化成对象即可
    • 本文前面节所举的案例,都是一次性的输入/输出,main函数只运行了一次
    • 但是实际工作中,特别是互朕网时代,绝大多数情况都是客户端与服务端之间的通讯,实际上输入/输出的通信量非常大,常常是几万、几十万个客户端与服务端通讯,服务端就必须并发响应客户端的请求
    • 那么服务端要如何做,才能并发响应呢?那么请看我还没有写笔记的Java多线程编程

发表评论

邮箱地址不会被公开。 必填项已用*标注