首页 > 编程语言 >java(17)java序列化和反序列化

java(17)java序列化和反序列化

时间:2023-02-01 23:25:35浏览次数:55  
标签:java 17 writeObject Student 序列化 public out

一、理解Java序列化和反序列化
Serialization(序列化):将java对象以一连串的字节保存在磁盘文件中的过程,也可以说是保存java对象状态的过程。序列化可以将数据永久保存在磁盘上(通常保存在文件中)。

deserialization(反序列化):将保存在磁盘文件中的java字节码重新转换成java对象称为反序列化。

二、序列化和反序列化的应用
两个进程在远程通信时,可以发送多种数据,包括文本、图片、音频、视频等,这些数据都是以二进制序列的形式在网络上传输。

java是面向对象的开发方式,一切都是java对象,想要在网络中传输java对象,可以使用序列化和反序列化去实现,发送发需要将java对象转换为字节序列,然后在网络上传送,接收方收到字符序列后,会通过反序列化将字节序列恢复成java对象。

java序列化的优点:
实现了数据的持久化,通过序列化可以把数据持久地保存在硬盘上(磁盘文件)。
利用序列化实现远程通信,在网络上传输字节序列。
三、序列化和反序列化地实现
1.JDK类库提供的序列化API:

java.io.ObjectOutputStream
表示对象输出流,其中writeObject(Object obj)方法可以将给定参数的obj对象进行序列化,将转换的一连串的字节序列写到指定的目标输出流中。
java.io.ObjectInputStream
该类表示对象输入流,该类下的readObject(Object obj)方法会从源输入流中读取字节序列,并将它反序列化为一个java对象并返回。
序列化要求:

实现序列化的类对象必须实现了Serializable类或Externalizable类才能被序列化,否则会抛出异常。

序列化要求:

实现序列化的类对象必须实现了Serializable类或Externalizable类才能被序列化,否则会抛出异常。

实现java序列化和反序列化的三种方法

现在要对student类进行序列化和反序列化,遵循以下方法:

方法一:若student类实现了serializable接口,则可以通过objectOutputstream和objectinputstream默认的序列化和反序列化方式,对非transient的实例变量进行序列化和反序列化。

方法二:若student类实现了serializable接口,并且定义了writeObject(objectOutputStream out)和

readObject(objectinputStream in)方法,则可以直接调用student类的两种方法进行序列化和反序列化。

方法三:若student类实现了Externalizable接口,则必须实现readExternal(Objectinput in)和writeExternal(Objectoutput out)方法进行序列化和反序列化。

JDK类库中的序列化步骤:

第一步:创建一个输出流对象,它可以包装一个输出流对象,如:文件输出流。

 

ObjectOutputStream out = new ObjectOutputStream(new fileOutputStream("E:\\JavaXuLiehua\\Student\\Student1.txt"));


 第二步:通过输出流对象的writeObject()方法写对象

out.writeObject("hollo word");

out.writeObject("happy")

JDK中反序列化操作:

第一步:创建文件输入流对象

ObjectInputStream in = new ObjectInputStream(new fileInputStream("E:\\JavaXuLiehua\\Student\\Student1.txt"));

 第二步:调用readObject()方法

String obj1 = (String)in.readObject();

 String obj2 = (String)in.readObject();

为了保证正确读取数据,对象输出流写入对象的顺序与对象输入流读取对象的顺序一致。

Student类序列化和反序列化演示:

import java.io.Serializable;            //导入io包下的序列化类
 
//创建实现序列化接口的学生类
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;
    }
}

把Student类的对象序列化到txt文件(E:\\JavaXuLiehua\\Student\\Student1.txt)中,并对文件进行反序列化:

import java.io.*;
import java.io.Externalizable;
/*
把student类对象序列化到文件E:\\JavaXuLiehua\\Student\\Student1.txt
 */
public class UserStudent {
    public static void main(String[] args) throws IOException {
        Student st = new Student("Tom",'M',20,3.6);         //实例化student类
        //判断Student1.txt是否创建成功
        File file = new File("E:\\JavaXuLiehua\\Student\\Student1.txt");
        if(file.exists()) {
            System.out.println("文件存在");
        }else{
            //否则创建新文件
            file.createNewFile();
        }
        try {
            //Student对象序列化过程
            FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            //调用 ObjectOutputStream 中的 writeObject() 方法 写对象
            oos.writeObject(st);
            oos.flush();        //flush方法刷新缓冲区,写字符时会用,因为字符会先进入缓冲区,将内存中的数据立刻写出
            fos.close();
            oos.close();
 
            //Student对象反序列化过程
            FileInputStream fis = new FileInputStream(file);
            //创建对象输入流
            ObjectInputStream ois = new ObjectInputStream(fis);
            //读取对象
            Student st1 = (Student) ois.readObject();           //会抛出异常(类找不到异常)
            System.out.println("name = " + st1.getName());
            System.out.println("sex = " + st1.getSex());
            System.out.println("year = " + st1.getYear());
            System.out.println("gpa = " + st1.getGpa());
            ois.close();
            fis.close();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
    }
}

transient关键字

transient关键字表示有理的,被修饰的数据不能进行序列化

这里不做详细介绍,修改情况如下:

private transient char sex;         //被transient关键字修饰,不参与序列化

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

具体代码实现如下:

复制对象student命名为student1,在里面重写writeExternal()方法和readExternal()方法,如下:

   @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()方法

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

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

 



标签:java,17,writeObject,Student,序列化,public,out
From: https://www.cnblogs.com/zhbx/p/17084447.html

相关文章

  • drf 序列化与反序列化 接口
    基于APIView编写5个接口之前是基于django的原生View编写接口现在用基于drf的APIView编写接口#drf提供了一个APIView类,以后用drf写视图类都是继承这个类或其子类,APIVie......
  • java(16)java异常
    异常指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。简单来说就是程序在运行时的时候,发生的不正常事件,就是所谓的异常。异常,:在J......
  • drf入门——APIView执行流程、Request对象源码分析、序列化器、反序列化及其校验
    drf入门——APIView执行流程、Request对象源码分析、序列化器、反序列化及其校验目录drf入门——APIView执行流程、Request对象源码分析、序列化器、反序列化及其校验APIV......
  • 【基础知识笔记】017 数组和矩阵的操作-上
    数组是MATLAB数据进行存储和处理的基本形式。矩阵是特殊形式的数组。数组与矩阵的操作是MATLAB语言的基础与特色所在1.数组(矩阵)的生成1.1直接生成矩阵的生成可以通......
  • drf APIView执行流程,Request对象源码分析,序列化器介绍与使用
    昨日内容回顾restful规范1接口使用https协议传输数据保证数据的安全性2接口带api标识3接口带版本信息4接口地址即资源,尽量使用名字,或复数,特殊情况可以使用动词5接口......
  • APIView执行流程、Request对象源码分析、序列化器介绍和快速使用、反序列化、反序列化
    APIView执行流程、Request对象源码分析、序列化器介绍和快速使用、反序列化、反序列化的校验APIView执行流程1.APIViewdrf只能在django上进行使用,安装了drf之后,导入一个......
  • JavaScript逻辑运算符:与(&&)和或(||)
    前置知识:在javascript的逻辑运算中,0、""、null、undefined和NaN都会判定为false,其它都为true或||用于判断运算的操作数可以是任意类型的值。操作数是布尔值时,除了两......
  • java(15)java数据保存
    存储数据1.寄存器(register)。这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。但是寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直......
  • APIView执行流程与序列化器
    drf整体内容#1入门规范 -web开发模式-api接口-接口测试工具-restful规范-序列化反序列化-drf快速使用-APIView,Request类-drf把dja......
  • Java(14)数组
    一、数组的基本概念1、什么是数组数组是相同类型元素的集合。创建数组的时候,Java就会再内存中分配一段连续的空间来存放数组的内容。每一个数组内容都有自己的编号,这......