序列化与反序列化复杂数据的两种方式
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