序列化与反序列化

一、概念

  • 序列化: 将数据结构或对象转换成二进制字节流的过程
  • 反序列化:将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程
    序列化和反序列针对的是对象。

序列化的用途:
(1)序列化可以将对象转化成字节流后存储在磁盘中,在需要的时候反序列化还原成对象,节约了内存空间。
(2)使用深克隆中使用。

二、static与transient

使用 transient 关键字修饰:
transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。

  • transient 只能修饰变量,不能修饰类和方法。
  • transient 修饰的变量,在反序列化后变量值将会被置成类型的默认值。例如,如果是修饰 int 类型,那么反序列后结果就是 0

使用static关键字修饰:
static 变量因为不属于任何对象(Object),所以无论有没有 transient 关键字修饰,均不会被序列化。

值得注意的是,二者还是有区别的,使用了transient修饰的字段,序列化结果是默认值,对象修改属性值后反序列仍然为默认值,即序列化结果。但static修饰的字段,对象属性修改后为实时值,不受序列化结果影响。

虽然对象的static属性不受序列化影响,但是静态类的对象同样可以进行序列化和反序列化。

三、序列化UID问题

序列化的UID是用于在翻序列化的过程中比对类的UID是否与本地一致,如果没有指定UID,该类被修改过则会重新用摘要算法生成新的UID,会出现无法与本地UID匹配的问题,导致加载失败,所以一般我们会指定serialVersionUID,保证在类修改后,仍能正常加载,不同的类可以指定相同的UID,原因是只在该类运行过程中进行判断,不会涉及其他类。

    private final static Long serialVersionUID = 1L;

四、实践

User实体类

package serialize.ex01;

import java.io.Serializable;

public class User implements Serializable {
    //序列化ID,字段名不能错
    private static final long serialVersionUID = 1L;

    private String name = "AAA";
    private int age;

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

    public User() {
    }

    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;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类

package serialize.ex01;

import java.io.*;
import java.lang.reflect.InvocationHandler;

public class Test {
    public static void main(String[] args)  {
        User user = new User();
        user.setAge(18);
        user.setName("CCC");
//        序列化
        try(FileOutputStream fileOutputStream = new FileOutputStream(new File("C:\\Users\\siuguan\\Desktop\\studentObj.txt"));
            ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream)) {
            outputStream.writeObject(user);
            System.out.println("序列化成功");
        }catch (IOException e){
            e.printStackTrace();
        }
        //反序列化
        try(FileInputStream fileInputStream = new FileInputStream(new File("C:\\Users\\siuguan\\Desktop\\studentObj.txt"));
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)){
            User user1 = (User) objectInputStream.readObject();
            System.out.println(user1);
        }catch (IOException | ClassNotFoundException e){
            e.printStackTrace();
        }
    }
}

执行结果:

序列化成功
User{name='CCC', age=18}

值得注意的是,要指定serialVersionUID ,如果不指定的话,序列化ID将有默认的摘要算法生成,因此,对象发生改变时,序列化ID又再次生成了一次,两次的序列化ID不同,会导致反序列化的时候出错。

private static final long serialVersionUID = 1L;

如果把User的属性修改成:

    private transient String name;
    private static int age;

则name序列化后null,而age则不受序列化影响,即在序列化修改age的值,那么对象的值为修改后的值。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值