JAVA进阶教学之(序列化和反序列化)

本文详细介绍了JAVA中的序列化和反序列化概念,包括序列化是将Java对象转换为数据流以便存储或传输,反序列化则是相反过程。文章通过代码示例展示了如何进行序列化和反序列化操作,强调了实现Serializable接口的重要性。同时,解释了序列化版本号的作用,并提到了transient关键字,用于排除特定属性参与序列化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 

1、序列化Serialize和反序列化的概念

2、序列化和反序列化的代码演示:

3、序列化多个对象(序列化集合)

4、transient关键字将部分属性不参与序列化


 

 

1、序列化Serialize和反序列化的概念

在内存和硬盘的数据交互过程中,将Java对象拆分的过程

序列化就是将Java内存中的Java对象切割成像序列一样传递到硬盘文件中存储 (拆分对象)

反序列化就是通过硬盘序列好的Java对象组装重新返回到Java内存中(组装对象)

 

图示:

 

2、序列化和反序列化的代码演示:

序列化:

通过代码演示来加深理解:

首先创建一个普通的Student学生类,这个学生类没有实现任何接口,就是普通的:

package com.lbj.javase.bean;

import java.io.Serializable;


public class Student{
    private int no;
    private String name;

    public Student() {
    }

    public Student(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

    //重写toString方法

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

 

再创建一个测试类,将Student对象进行序列化:

package com.lbj.javase.bean;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class ObjectOutputStreamTest01{
    public static void main(String[] args) throws Exception{
        //创建java对象
        Student s=new Student(123,"zhangsan");

        //包装类
        FileOutputStream fos=new FileOutputStream("student");

        //序列化
        ObjectOutputStream oos=new ObjectOutputStream(fos);

        //序列化对象
        oos.writeObject(s);

        //刷新
        oos.flush();

        //关闭
        oos.close();

    }
}

报错:

总结:

Student是一个普通的类,并不支持序列化,需要加上Serializable的实现结构

 

 

修改测试(此时的Student类实现了Serializable接口):

package com.lbj.javase.bean;

import java.io.Serializable;

//Serializable只是一个标志性接口,这个接口其实什么都不写
public class Student implements Serializable {
    private int no;
    private String name;

    public Student() {
    }

    public Student(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

    //重写toString方法

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

测试:

package com.lbj.javase.bean;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;


public class ObjectOutputStreamTest01{
    public static void main(String[] args) throws Exception{
        //创建java对象
        Student s=new Student(123,"zhangsan");

        //包装类
        FileOutputStream fos=new FileOutputStream("student");

        //序列化
        ObjectOutputStream oos=new ObjectOutputStream(fos);

        //序列化对象
        oos.writeObject(s);

        //刷新
        oos.flush();

        //关闭
        oos.close();

    }
}

测试结果:

总结:

1、参与序列化和反序列化的对象,必须实现Serializable接口

2、Serializable接口只是一个标志性接口,这个接口中什么也没有,只是起到让java虚拟机看到这个类实现了这个接口,可能对这个类特殊的待遇,java虚拟机会默认提供这个序列化的版本号(序列化版本号是用来区分序列化的类是否发生改变,用来达到安全性)

3、java虚拟机会自动序列化版本号,缺点。一旦被序列化的类A的代码确定后,不能进行后续的修改;只要修改,必定会重新编译,此时类A会生成全新的序列化版本号,这时候java虚拟机会认为这是一个全新的类(这样就不好了,会反序列化不成功,因为反序列化是根据序列化版本号进行重新读取)

4、结论:凡是一个类实现了Serializable接口,建议给该类一个固定不变的序列化版本号,这样,以后这个类即使代码修改了,但是版本号不变,java虚拟机会认为是同一个类(Idea中可以生成一个序列化版本号,自己去探索,或者自己写一个也行)(P756)

 

 

-----------------------------------------------------------------------------------------------------------------------------------

 

反序列化:

代码演示:

package com.lbj.javase.bean;

import java.io.FileInputStream;
import java.io.ObjectInputStream;


public class ObjectInputStreamTest01 {
    public static void main(String[] args) throws Exception{
        //包装类
        FileInputStream fis=new FileInputStream("student");

        //序列化
        ObjectInputStream ois=new ObjectInputStream(fis);

        //开始反序列化,读
        Object obj=ois.readObject();

        //输出obj内容
        //反序列化回来是一个学生对象,所以会调用学生对象的toString方法
        System.out.println(obj.toString());

        //关闭流
        ois.close();
    }
}

输出结果:

Student{no=123, name='zhangsan'}

 

 

3、序列化多个对象(序列化集合)

代码演示:

创建一个实现Serializeable接口的Student类:

package com.lbj.javase.bean;

import java.io.Serializable;


//Serializable只是一个标志性接口,这个接口其实什么都不写
public class Student implements Serializable {
    private int no;
    private String name;

    public Student() {
    }

    public Student(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

    //重写toString方法

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

 

序列化:

package com.lbj.javase.bean;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;


public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws Exception{
        //创建一个集合对象
        List<Student> list=new ArrayList<>();

        //添加集合数据
        list.add(new Student(111,"lisi"));
        list.add(new Student(222,"Wanwu"));
        list.add(new Student(333,"liliu"));

        //输出流
        FileOutputStream fos=new FileOutputStream("students");

        //序列化
        ObjectOutputStream oos=new ObjectOutputStream(fos);

        //序列化一个集合,这个杰辉对象中放了很多其他对象
        oos.writeObject(list);

        //刷新流
        oos.flush();

        //关闭流
        oos.close();
    }
}

 

反序列化:

package com.lbj.javase.bean;

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;


public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws Exception{
        //输入流
        FileInputStream fis=new FileInputStream("students");

        //反序列化
        ObjectInputStream ois=new ObjectInputStream(fis);

//        Object obj=ois.readObject();
//        System.out.println(obj.toString());

        //用列表形式输出
        List<Student> list = (List<Student>) ois.readObject();

        //集合的循环输出
        for (Student s:list
             ) {
            System.out.println(s);
        }

        //关闭流
        ois.close();

    }
}

 

结果:

Student{no=111, name='lisi'}
Student{no=222, name='Wanwu'}
Student{no=333, name='liliu'}

 

 

注意:如果不用集合,直接存储多个对象,在存储第二个对象的时候会报错

 

 

4、transient关键字将部分属性不参与序列化

transient表示游离的,不参与序列化,只要给属性加上此限制,即可

演示:

结果(数据变成null):

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值