Java基础学习笔记——序列化与反序列化

 本篇文章参考:

 JAVA 序列化、反序列化以及serialVersionUID_java serialversionuid-CSDN博客

Java 中序列化与反序列化,看这篇就够了!_java的序列化和反序列的定义-CSDN博客

引言:

Java的JDK中提供了对应的API,来实现序列化和反序列化,就是把对象转化为字节序列以及再转化会对象的功能,便于Java对象的持久化储存和在网络中的传输。

一、简单理解序列化与反序列化的原理

序列化(Serialization):就是把一个普通的Java对象(POJO)转化为特定的字节序列,通过序列化,可以将对象存储到文件中。

反序列化(Deserialization):就是把已经序列化为字节序列的Java对象再转化回对象的过程。在反序列化过程中,Java会读取字节序列中的信息重构对象,并将其重新加载到内存中。

计算机中,文件都是存储在硬盘(外存)中,除非你删除它,不然是会一直保存着的;且文件可以用来传输(例如微信,QQ上传输文件);因此,把Java对象序列化成文件可以实现Java对象持久化储存和在网络中的传输。

Java的序列化机制是通过实现java.io.Serializable接口来实现的。该接口是一个标记接口,没有定义任何方法。只有实现了Serializable接口的类创建的对象才能被序列化。

注意, 如果对象的某些属性不想被序列化,那么如何避免序列化呢?

1. 用static 修饰, 因为序列化操作只对于堆区 ,而static修饰的属性在全局区

2.用transient 修饰属性,java语法规定,transient关键字修饰的成员属性变量不被序列化

二、实现序列化与反序列化的代码过程

1.序列化对象

1.首先创建一个实现了Serializable接口类,该类的实例都将可以被序列化

2.创建一个ObjectOutputStream对象,用该对象中的writeObject()方法将要被序列化的对象写进输出流中

3.释放资源关闭输出流。

2.反序列化对象

  1. 创建一个ObjectInputStream对象,用于从字节流中读取对象。
  2. 使用readObject()方法从输入流中读取对象。
  3. 释放资源:关闭输入流。

代码实现:

创建一个实现了Serialization接口的类

package com.yzx.test;

import java.io.Serializable;

/**
 * 实现了序列化接口的学生类
 */
public class Student implements Serializable {
    private String name;
    private char sex;
    private int age;
 
    public Student() {
    }
    public Student(String name,char sex,int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public void setSex(char sex) {
        this.sex = sex;
    }
 
    public void setAge(int year) {
        this.age = year;
    }
 
    public String getName() {
        return this.name;
    }
 
    public char getSex() {
        return this.sex;
    }
 
    public int getAge() {
        return this.age;
    }

}

下面把该学生类的实例序列化,储存Test\src\student.txt文件中,并从该文件中反序列化,在控制台显示结果。代码如下:

package com.yzx.test;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class SerializeStudent {
    public static void main(String[] args) {
        Student student = new Student("小明",'男',18);
        File file = new File("D:\\eclipse-workspace\\TEST\\src\\student.txt");
        try {
            file.createNewFile();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        try {
            //对student对象序列化
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
            oos.writeObject(student);
            oos.flush();
            oos.close();
 
            //把student对象反序列化并用student1接收
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
            Student student1 = (Student) ois.readObject();
            System.out.println("name = " + student1.getName());
            System.out.println("sex = " + student1.getSex());
            System.out.println("age = " + student1.getAge());
          
            ois.close();

        }
        catch(ClassNotFoundException e) {
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

控制台输出:

而打开student.txt文本可看到被序列化的jstudent对象:

三、序列化ID问题

一般在序列化时,会对Student类加上一条 serialVersionUID 的属性如:

private static final long serialVersionUID = 1L;

如果不手动加这个 serialVersionUID,序列化过程中也会默认生成一个的,只是我们看不到。例如

private static final long serialVersionUID = -8567374045705746827L;

在序列化和反序列化过程中,这个serialVersionUID就像是这个类的身份证号码一样,具有唯一识别的性质。

案例:

原本我们的Student类只有3个成员变量;

然后我们进行了序列化, 这时候,默认生成对应的 serialVersionUID,绑定的内容就是这个有2个字段属性的student,已经序列化保存到Test\src\student.txt文件里面了。

现在我们在原来的基础上加一个成员变量: private String school;

 此时再来进行反序列化的操作时,就会报错,如下:

package com.yzx.test;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class SerializeStudent {
    public static void main(String[] args) {
        File file = new File("D:\\eclipse-workspace\\TEST\\src\\student.txt");
        try {
 
            //把原student对象反序列化,这次用修改后的Student类的实例student2接收
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
            Student student2 = (Student) ois.readObject();
            System.out.println("name = " + student2.getName());
            System.out.println("sex = " + student2.getSex());
            System.out.println("age = " + student2.getAge());
          
            ois.close();

        }
        catch(ClassNotFoundException e) {
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

报错的大体意思是:要反序列化的对象的 serialVersionUID与本地接收对象的  serialVersionUID不一致;

java.io.InvalidClassException: com.yzx.test.Student; local class incompatible: stream classdesc serialVersionUID = -1458264931033465272, local class serialVersionUID = -178992672213206791
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1963)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1829)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2120)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1646)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:482)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:440)
	at com.yzx.test.SerializeStudent.main(SerializeStudent.java:30)

 为避免这样的错误,我们一般手动加上一条 serialVersionUID 属性;

加上serialVersionUID之后的对象,序列化之后,无论之后怎么修改,只要serialVersionUID不变,反序列化就可以正常进行。


 

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值