序列化与反序列化复杂数据的两种方式(java原生和利用bytebuffer的方式)

1 篇文章 0 订阅
1 篇文章 0 订阅

序列化与反序列化复杂数据的两种方式

1、第一种序列化方式

1.1 Java 怎么进行序列化与反序列化?

  ①、需要做序列化的对象的类,必须实现序列化接口:Java.lang.Serializable 接口(这是一个标志接口,没有任何抽象方法),Java 中大多数类都实现了该接口,比如:String,Integer

  ②、底层会判断,如果当前对象是 Serializable 的实例,才允许做序列化,Java对象 instanceof Serializable 来判断。

  ③、在 Java 中使用对象流来完成序列化和反序列化

    ObjectOutputStream:通过 writeObject()方法做序列化操作

    ObjectInputStream:通过 readObject() 方法做反序列化操作

1.2 注意问题

问题1、如果某些数据不需要做序列化,比如密码,比如上面的年龄?

解决办法:在字段面前加上 transient

private String name;//需要序列化

transient private int age;//不需要序列化

问题2、序列化版本问题,在完成序列化操作后,由于项目的升级或修改,可能我们会对序列化对象进行修改,比如增加某个字段,那么我们在进行反序列化就会报错:

解决办法:在 JavaBean 对象中增加一个 serialVersionUID 字段,用来固定这个版本,无论我们怎么修改,版本都是一致的,就能进行反序列化了

private static final long serialVersionUID = 2L; 

1.3 测试Demo

①、 要进行序列化的对象类Model,包含age和name两个属性,具体定义如下:

package serializabletest;

import java.io.*;

/**
 * Created by 0262000099 on 2018/9/6.
 */
public class Model implements Serializable {
  private static final long serialVersionUID = 1L;
  private int age;
  private String name;

  public int getAge() {
    return age;
  }

  public String getName() {
    return name;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public void setName(String name) {
    this.name = name;
  }
}

②、测试类ConvertFunctionTest

package serializabletest;

import java.io.*;

/**
* @Description    ConvertFunctionTest Function Descripition {该类主要有两个方法组成,分贝是序列化和反序列化方法}
* @Author         0262000099 Hengtai Nie
* @CreateDate     2018/9/6 14:00
*/
public class ConvertFunctionTest {

  /**
   * @Description    toByte Function Descripition {}
   * @Author:        0262000099 Hengtai Nie
   * @CreateDate     2018/9/6 15:22
   * @Params         [model]
   * @Return         byte[]
   */
  public byte[] toByte( Model model) {

//    输出流ByteArrayOutputStream是跟字节进行交互的
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//    输出流ObjectOutputStream是跟对象进行交互的,可以把对象转换为ByteArrayOutputStream输出流
//    ObjectOutputStream objectOutputStream ;
    byte[] bytes = null;

    ObjectOutputStream objectOutputStream = null;
    try {
      objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
      objectOutputStream.writeObject(model);
      bytes = byteArrayOutputStream.toByteArray();
      byteArrayOutputStream.close();
//      System.out.println("序列化后的字节数组是:" + bytes);
    } catch (IOException e) {
      e.printStackTrace();
    }
    return bytes;
  }

  /**
   * @Description     fromByte() Descripition {反序列化对象}
   * @Author:        0262000099 Hengtai Nie
   * @CreateDate     2018/9/6 11:29
   * @Params         序列化后的字节数组bytes
   * @Return         返回对象model
   */
  public Model fromByte(byte [] bytes) throws ClassNotFoundException {

    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
    Model model = null;
    try {
      ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
      objectInputStream.close();
      model = (Model) objectInputStream.readObject();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return model;
  }

  // 主函数测试序列化和反序列化
  public static void main (String[] args) throws ClassNotFoundException {
    Model model = new Model();
    model.setName("那个她");
    model.setAge(18);
    System.out.println("序列化前的对象:" + model);
    ConvertFunctionTest test = new ConvertFunctionTest();
    byte[] bytes = test.toByte(model);
    System.out.println("序列化后的字节数组是:" + bytes);

    Model modelDe = test.fromByte(bytes);
    System.out.println("反序列化后的对象:" + "\n" + "name:" + modelDe.getName() + "\n" + "age:" + modelDe.getAge());
  }

}

上述代码输出结果:

序列化前的对象:serializabletest.Model@4554617c

序列化后的字节数组是:[B@4b67cf4d

反序列化后的对象:

name:那个她

age:18

2、第二种序列化方式

①、要序列化的类SerializedClass, 包含age和name两个属性,具体定义如下:

package bytebufferserializetest;

import java.io.Serializable;

/**
 * Created by 0262000099 on 2018/9/6.
 */
public class SerializedClass implements Serializable{
  private static final long serialVersionUID = 2L;
  private String name ;
  private int age ;

  public SerializedClass() {
  }

  public SerializedClass(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public static long getSerialVersionUID() {
    return serialVersionUID;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

}

② 、序列化与反序列化原理:

package bytebufferserializetest;

import java.nio.ByteBuffer;

/**
 * Created by 0262000099 on 2018/9/6.
 */
public class SerializeClassTest {

/**
 * 序列化过程:
 *将int age 放入固定大小的ByteBuffer(字节数组)首部部分空间,占用ByteBuffer长度为4字节。将String name 转换成字节数组(serializedClass.getName().getBytes()),得到str.getBytes()的长度(serializedClass.getName().getBytes().length())。另外用4个字节(就是int长度)的ByteBuffer空间存放name字节数组的大小。
 *再用上serializedClass.getName().getBytes().length()长度的空间存放serializedClass.getName().getBytes()。
 *所以总的ByteBuffer大小为sizeof(int)+ sizeof(int)+str.getBytes().length()。
 *占用空间大小
 *sizeof(int)   占用空间大小
 *sizeof(int)
 *占用空间大小
 *serializedClass.getName().getBytes().length()
 *
*/
  public ByteBuffer Serialize(SerializedClass serializedClass)
  {
    int length = serializedClass.getName().length();
    System.out.println("name length:" + length);

    ByteBuffer byteBuffer = ByteBuffer.allocate( 4 + 4 + length );

    byteBuffer.putInt(serializedClass.getAge());
    byteBuffer.putInt(length);
    byteBuffer.put(serializedClass.getName().getBytes());
    System.out.println("byteBuffer:" + byteBuffer);
    return byteBuffer;
  }

  /**
   * 反序列化过程:
   将首部大小为sizeof(int)的数据取出ByteBuffer.getInt()。还原成int age= ByteBuffer.getInt();将第二个sizeof(int)大小的数据取出int length= ByteBuffer.getInt();length是name字节数组大小。
   byte[] bytes = new byte[length];buffer.get(bytes);然后还原String name = new String(bytes, "UTF-8");最后还原成class SerializedClass 的对象。
   *
   */

  public SerializedClass deSerialize(ByteBuffer byteBuffer)
  {
    SerializedClass serializedClass = null;
    byteBuffer.position(0);
    int age = byteBuffer.getInt();
    System.out.println("age:" + age);
    int length = byteBuffer.getInt();
    System.out.println("name length:" + length);
    try
    {
      byte[] bytes = new byte[length];
      byteBuffer.get(bytes);
      serializedClass = new SerializedClass(new String(bytes, "UTF-8"), age);
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
    System.out.println("SerializedClass:" + "\n" + "age:" + serializedClass.getAge() + "\n" + "name:" + serializedClass.getName() );
    return serializedClass;
  }


  public static void main (String[] args) {

    SerializedClass serializedClass = new SerializedClass();
    serializedClass.setAge(20);
    serializedClass.setName("flower");

    SerializeClassTest serializeClassTest = new SerializeClassTest();
    ByteBuffer byteBuffer = serializeClassTest.Serialize(serializedClass);
    System.out.println("序列化之后的bytebuffer:" + byteBuffer);

    SerializedClass serializedClassDe = serializeClassTest.deSerialize(byteBuffer);
    System.out.println("反序列化之后的对象:" + "\n" + "age:" + serializedClassDe.getAge() + "\n" + "name:" + serializedClassDe.getName());
  }
}

运行结果如下:

name length:6

byteBuffer:java.nio.HeapByteBuffer[pos=14 lim=14 cap=14]

序列化之后的bytebuffer:java.nio.HeapByteBuffer[pos=14 lim=14 cap=14]

age:20

name length:6

SerializedClass:

age:20

name:flower

反序列化之后的对象:

age:20

name:flower

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值