一、序列化的含义及作用
含义:
- 序列化:将Java对象转换成字节序列
- 反序列化:将字节序列转换成Java对象
作用:
- 字节序列可用于网络传输
- 可将Java对象持久化到存储介质中(比如硬盘)
二、序列化常用方式
1. 实现Serializable接口
要点:
- serialVersionUID的作用是验证序列化前后对象版本一致性;
- 静态变量 和 被 transient 修饰的变量不会被序列化。transient 只能修饰变量,不能修饰类和方法
2. 实现Externalizable接口
要点:
- 需要提供public的无参构造方法
- 需要实现writeExternal() 和 readExternal () 方法,且writeExternal()写入的参数类型数量大于等于readExternal()读出的
- 特殊现象:静态变量 和 被 transient 修饰的变量测试发现可以被序列化
(笔者暂无法解释,先抛砖引玉,请各位大神不吝赐教)
注意:Externalizable接口继承Serializable
三、演示代码
- 实现Serializable接口序列化测试
/**
* @author :alen_小鹿
* @date :Created in 2022/1/14 2:45 下午
* @description:实现Serializable接口序列化测试
*/
/*
* 摘要:
* 一、序列化和反序列化含义及作用
* 1、含义:序列化:对象转换成字节序列;反序列化:字节序列转成对象
* 2、作用:字节序列可在网络传输;对象持久化到存储介质(比如硬盘)中
* 二、用Serializable实现序列化,有两个要点:
* 1、serialVersionUID的作用是验证序列化前后对象版本一致性;
* 2、静态变量 和 被 transient 修饰的变量不会被序列化
*
* */
public class SerializableTest implements Serializable {
public static int age;
public transient String address;
public String name;
public int money;
private static final long serialVersionUID = 1111013L;
public SerializableTest() {
/**
*
* @description 不需要提供一个public 的无参构造方法
* @author alen_小鹿
* @date 2022/1/14 4:23 下午
* @param []
* @return
*
**/
System.out.println("进入无参构造方法");
}
public SerializableTest(int age, String address, String name, int money) {
System.out.println("进入有参构造方法");
this.age = age;
this.address = address;
this.name = name;
this.money = money;
}
@Override
public String toString() {
return "SerializableTest{" +
"address='" + address + '\'' +
", name='" + name + '\'' +
", money=" + money +
", age='" + age + '\'' +
'}';
}
public static void main(String[] args) {
serialize();
deserialize();
/*
serialVersionUID的作用是验证序列化前后对象版本一致性
1、前后对象字段一致
有无serialVersionUID结果一致
2、前后对象字段不一致,
无serialVersionUID会报错,
有serialVersionUID时,字段以后面对象为准,值以前面对象为准。
后面对象多的字段初始化(String 为 null,int 为 0,static修饰的字段除外,取其实际赋值)
*/
}
/**
* @param
* @return void
* @description 序列化
* @author alen_小鹿
* @date 2022/1/14 2:56 下午
**/
public static void serialize() {
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/alen_小鹿/souce/svnM/TestFile/serializable.txt"));
SerializableTest t = new SerializableTest(10, "北京", "张三", 100);
System.out.println("序列化前对象=" + t);
oos.writeObject(t);
/*
t.age = 20;
t.setAddress("广州");
t.setName("李四");
t.setMoney(200);
静态变量 和 被 transient 修饰的变量不会被序列化
age 改成 20,静态变量不属于对象实例,不会被序列化
address 为 null,被transient(短暂的)修饰,不会被序列化
name 和 money 值不改,因已持久化,取持久化的旧值
*/
} catch (IOException e) {
System.out.println(e);
}
}
/**
* @param
* @return void
* @description 反序列化
* @author alen_小鹿
* @date 2022/1/14 2:56 下午
**/
public static void deserialize() {
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/alen_小鹿/souce/svnM/TestFile/serializable.txt"));
SerializableTest t = (SerializableTest) ois.readObject();
System.out.println("序列化后对象=" + t);
} catch (IOException | ClassNotFoundException e) {
System.out.println(e);
}
}
}
- 实现Externalizable接口序列化测试
/**
* @author :alen_小鹿
* @date :Created in 2022/1/14 3:00 下午
* @description:实现Externalizable接口序列化测试
*/
/*
* 摘要:Externalizable实现序列化,有两个要点:
* 1、需要提供public的无参构造方法
* 2、需要实现writeExternal()和readExternal()方法,且writeExternal()写入的参数类型数量大于等于readExternal()读出的
*
* */
public class ExternalizableTest implements Externalizable {
public int age;
public String address;
public String name;
public int money;
private static final long serialVersionUID = 1111013L;
/**
* @param
* @return
* @description 提供一个 public 无参构造方法
* @author alen_小鹿
* @date 2022/1/14 4:20 下午
**/
public ExternalizableTest() {
System.out.println("进入无参构造方法");
}
public ExternalizableTest(int age, String address, String name, int money) {
System.out.println("进入有参构造方法");
this.age = age;
this.address = address;
this.name = name;
this.money = money;
}
@Override
public String toString() {
return "ExternalizableTest{" +
"name='" + name + '\'' +
", age=" + age +
", money=" + money +
", address='" + address + '\'' +
'}';
}
/**
* @param out
* @return void
* @description 实现接口Externalizable的writeExternal方法
* @author alen_小鹿
* @date 2022/1/14 4:21 下午
**/
@Override
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("序列化写入");
out.writeObject(name);
out.writeInt(age);
out.writeObject(address);
}
/**
* @param in
* @return void
* @description 实现接口Externalizable的readExternal方法
* @author alen_小鹿
* @date 2022/1/14 4:21 下午
**/
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("反序列化读出");
name = (String) in.readObject();
age = in.readInt();
}
public static void main(String[] args) {
enternalize();
deEnternalize();
}
/**
* @param
* @return void
* @description 序列化写入
* @author alen_小鹿
* @date 2022/1/14 4:19 下午
**/
public static void enternalize() {
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/alen_小鹿/souce/svnM/TestFile/enternalizable.txt"));
ExternalizableTest t = new ExternalizableTest(10, "北京", "张三", 100);
oos.writeObject(t);
System.out.println("序列化前对象=" + t);
} catch (IOException e) {
System.out.println(e);
}
}
/**
* @param
* @return void
* @description 反序列化读出
* @author alen_小鹿
* @date 2022/1/14 4:19 下午
**/
public static void deEnternalize() {
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/alen_小鹿/souce/svnM/TestFile/enternalizable.txt"));
ExternalizableTest t = (ExternalizableTest) ois.readObject();
System.out.println("序列化后对象=" + t);
} catch (IOException | ClassNotFoundException e) {
System.out.println(e);
}
}
}