一,Java序列化与反序列化

1.Serialization(序列化):
Java序列化是指将Java对象转换为字节流的过程,以便将对象的状态保存到文件、数据库或通过网络传输。序列化后的字节流包含对象的数据及其类型信息,使得对象可以在不同JVM或环境中重建。

2.deserialization(反序列化):
Java反序列化是指将序列化后的字节流重新转换为Java对象的过程,恢复对象原有的状态和数据。反序列化通过读取字节流并重建对象的内存结构来实现。

二,序列化以及反序列化的应用

  • 对象持久化(保存到文件)
  • 网络传输(RPC、Socket)
  • 缓存(Redis 存储对象)
  • 消息队列(RabbitMQ、RocketMQ 传输对象)
  • 分布式 Session 共享
Java序列化的优点:
  • 便于对象持久化,可以将对象保存到文件或数据库。
  • 支持网络传输,方便对象在不同系统之间传递。
  • 适用于分布式系统,实现远程调用、Session 共享等。
  • 实现简单,对象实现 Serializable 接口即可进行序列化。

三,序列化与反序列化的实现

1.向文件中写入字符串

序列化操作:

首先是创建这个字节输出流来指向你所要操作的文件,然后创建OutputStreamWriter将字节流转换为字符流,并按照utf-8的字符集进行写入,然后再加一个BufferWriter来增加一个缓冲区来增加写入效率,使用这个write方法进行写入字符串,然后调用flush方法,强制将缓冲区中的数据立即写入文件,最后使用close方法关闭流并且释放资源。

@Test
    public void test_out_serialization() {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("D:\\Java\\Java-demo\\src\\test\\resources\\Student1.txt");
            OutputStreamWriter outputStreamWriter=new OutputStreamWriter(fileOutputStream,StandardCharsets.UTF_8);
            BufferedWriter bufferedWriter=new BufferedWriter(outputStreamWriter);
            bufferedWriter.write("hello world1");
            bufferedWriter.flush();
            bufferedWriter.close();
        }catch (IOException e){
            System.out.println(e.getMessage());
        }
        System.out.println("ok");
    }

写入后的效果:

反序列化操作:

首先是创建这个字节输入流来指向你所要操作的文件,然后创建InputStreamReader将字节流转换为字符流,并按照utf-8的字符集进行写入,然后再加一个BufferReader来增加一个缓冲区来增加读取效率,使用这个readLine方法进行读取一行字符串,最后使用close方法关闭流并且释放资源。

@Test
    public void test_in_serialization() {
        try {
            FileInputStream fileInputStream = new FileInputStream("D:\\Java\\Java-demo\\src\\test\\resources\\Student1.txt");
            InputStreamReader inputStreamReader =new InputStreamReader(fileInputStream,StandardCharsets.UTF_8);
            BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
            String read = bufferedReader.readLine();
            bufferedReader.close();
            System.out.println(read);
        }catch (IOException e){
            System.out.println(e.getMessage());
        }
        System.out.println("ok");
    }

读取后的效果:

2.向文件中写入对象

首先要创建一个实体类,然后这个类要实现Serializable接口

package com.cat.entity;

import java.io.Serializable;

public class Student implements Serializable {
    //私有化成员变量
    private String name;
    private char sex;
    private  int year;
    private  double gpa;

    public Student(){   //无参构造
    }
    public Student(String name,char sex,int year,double gpa){
        //参数给属性赋值
        this.name = name;
        this.sex = sex;
        this.year = year;
        this.gpa = gpa;
    }

    //重写set和get
    public String getName() {
        return name;
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public double getGpa() {
        return gpa;
    }

    public void setGpa(double gpa) {
        this.gpa = gpa;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex=" + sex +
                ", year=" + year +
                ", gpa=" + gpa +
                '}';
    }
}

序列化操作

首先是创建一个实体类对象,然后再创建这个字节输出流来指向你所要操作的文件,然后再创建一个ObjectOutputStream对象输出流将Java对象转换为字节流,使用这个writeObject方法进行写入对象,然后调用flush方法,强制将缓冲区中的数据立即写入文件,最后使用close方法关闭流并且释放资源。

@Test
    public void test_out_object_serialization() throws IOException {
        Student student=new Student("cat",'M',21,3.6);
        File file = new File("D:\\Java\\Java-demo\\src\\test\\resources\\Student1.txt");
        if (file.exists()){
            System.out.println("文件存在");
        }else {
            file.createNewFile();
        }
        try {
            FileOutputStream fos=new FileOutputStream(file);
            ObjectOutputStream oos=new ObjectOutputStream(fos);
            oos.writeObject(student);
            oos.flush();
            fos.close();
            oos.close();
        }catch (IOException e){
            System.out.println(e.getMessage());
        }
        System.out.println("ok");
    }

写入后的效果:

从这里可以看出序列化的内容是很难读取的,是要靠反序列化进行读取的

反序列化操作:

首先创建这个字节输入流来指向你所要操作的文件,然后再创建一个ObjectInputStream对象输入流将字节流转换为Java对象,使用这个readObject方法进行写入对象,然后调用flush方法,强制将缓冲区中的数据立即写入文件,最后使用close方法关闭流并且释放资源。

@Test
    public void test_in_object_serialization() throws IOException {
        File file = new File("D:\\Java\\Java-demo\\src\\test\\resources\\Student1.txt");
        if (file.exists()){
            System.out.println("文件存在");
        }else {
            file.createNewFile();
        }
        try {
            FileInputStream fis=new FileInputStream(file);
            ObjectInputStream ois=new ObjectInputStream(fis);
            Student student = (Student) ois.readObject();
            System.out.println(student);
            ois.close();
            fis.close();
        }catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        System.out.println("ok");
    }

结果如下:

四,transient关键字

被transient关键字修饰的属性,不能被序列化

这里给sex属性加了transient关键字,这里要注意序列化的实体类发生了改变,要将文件中的内容删除,重新序列化一遍这个实体类才可以,要不然反序列化时会报错

可以看到这时sex字段的值变为空值,没有被序列化

五,Externalizable接口实现序列化与反序列化

Externalizable接口继承Serializable接口,实现Externalizable接口需要实现readExternal()方法和writeExternal()方法,这两个方法是抽象方法,对应的是serializable接口的readObject()方法和writeObject()方法,可以理解为把serializable的两个方法抽象出来。Externalizable没有serializable的限制,static和transient关键字修饰的属性也能进行序列化。
在实体类中重写这两个方法

   @Override
    //对抽象方法进行重写
    public void writeExternal(ObjectOutput out) throws IOException{
        out.writeObject(name);
        out.writeObject(sex);
        out.writeObject(year);
        out.writeObject(gpa);
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
        sex = (char) in.readObject();
        year = (int) in.readObject();
        gpa = (double) in.readObject();
    }

相应的测试方法里面调用这两种方法的时候,直接调用writeObject()方法和readObject()方法即可,重写的writeExternal()和readExternal()方法会自动执行。

FileOutputStream fos1 = new FileOutputStream(file1);
                ObjectOutputStream oos1 = new ObjectOutputStream(fos1);
                //调用 ObjectOutputStream 中的 writeObject() 方法 写对象
                oos1.writeObject(st);       //会自动执行重写的writeExternal()方法
FileInputStream fis1 = new FileInputStream(file1);
                //创建对象输入流
                ObjectInputStream ois1 = new ObjectInputStream(fis1);
                //读取对象
                //会自动执行readExternal()方法
                Student1 st1 = (Student1) ois1.readObject();           //会抛出异常(类找不到异常)

虽然student类里的sex属性被static或transient修饰,但依旧被序列化,结果如下:

文件存在
name = cat
sex = M
year = 20
gpa = 3.6

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐