详解 序列化流 与 反序列化流

目录

  • 序列化流 与 反序列化流

    • ObjectOutputStream 类:
    • (序列化流)
    • ObjectInputStream 类:
    • (反序列化流):

(请观看本人博文——《详解 I/O流》



@


序列化流 与 反序列化流

可能同学们看到本篇博文时会有如下问题:
什么是 序列化 与 反序列化 呢?

那么,现在,本人就来讲解下这两个名词的定义:

  • 序列化:
    就是把对象通过流的方式存储到文件中
  • 反序列化:
    就是把文件中存储的对象以流的方式还原成对象

现在,本人再来介绍下这两个流的作用:

ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,
可以为应用程序提供对对象图形的持久存储
而且,被存储的对象的类必须继承java.io.Serializable接口,否则无法读取所存储的数据

在讲解这两个流之前,本人现要讲解下 transient 关键字

transient 关键字:
被修饰的成员,在 不会被序列化。
所以当我们用序列化流去存储后,在读取时,所得到的结果 和 我们读取未赋值的成员的结果一样。

那么,现在,本人就分别对这两个流进行下讲解:



首先是 序列化流(ObjectOutputStream 类):

ObjectOutputStream 类:

(序列化流)

概述

此类 是将 Java对象的基本数据类型 和 图形 写入 OutputStream
可以使用 ObjectInputStream 读取(重构)对象
通过在流中使用文件可以实现对象的持久存储
如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象

现在,本人来展示下这个类的构造方法

构造方法

  • protected ObjectOutputStream()
    为完全重新实现 ObjectOutputStream 的子类提供一种方法,
    让它不必分配仅由 ObjectOutputStream 的实现使用的私有数据
  • ObjectOutputStream(OutputStream out)
    创建写入指定 OutputStream 的 ObjectOutputStream

那么,本人来展示下这个类的 常用API

常用API

  • protected void annotateClass(Class<?> cl)
    子类可以实现此方法,从而允许在流中存储类数据
  • protected void annotateProxyClass(Class<?> cl)
    子类可以实现此方法,从而在流中存储 定制数据动态代理类的描述符
  • void close()
    关闭流
  • void defaultWriteObject()
    将当前类的非静态和非瞬态字段写入此流
  • protected void drain()
    排空 ObjectOutputStream 中的所有已缓冲数据
  • protected boolean enableReplaceObject(boolean enable)
    允许流对流中的对象进行替换
  • void flush()
    刷新该流的缓冲
  • ObjectOutputStream.PutField putFields()
    获取用于缓冲写入流中的持久存储字段的对象
  • protected Object replaceObject(Object obj)
    在序列化期间,
    此方法允许 ObjectOutputStream 的受信任子类使用一个对象替代另一个对象
  • void reset()
    重置将丢弃已写入流中的所有对象的状态
  • void useProtocolVersion(int version)
    指定要在写入流时使用的流协议版本
  • void write(byte[] buf)
    写入一个 byte 数组
  • void write(byte[] buf, int off, int len)
    写入字节的子数组
  • void write(int val)
    写入一个字节
  • void writeBoolean(boolean val)
    写入一个 boolean 值
  • void writeByte(int val)
    写入一个 8 位字节
  • void writeBytes(String str)
    以字节序列形式写入一个 String
  • void writeChar(int val)
    写入一个 16 位的 char 值
  • void writeChars(String str)
    以 char 序列形式写入一个 String
  • protected void writeClassDescriptor(ObjectStreamClass desc)
    将指定的类描述符写入 ObjectOutputStream
  • void writeDouble(double val)
    写入一个 64 位的 double 值
  • void writeFields()
    将已缓冲的字段写入流中
  • void writeFloat(float val)
    写入一个 32 位的 float 值
  • void writeInt(int val)
    写入一个 32 位的 int 值
  • void writeLong(long val)
    写入一个 64 位的 long 值
  • void writeObject(Object obj)
    将指定的对象写入 ObjectOutputStream
  • protected void writeObjectOverride(Object obj)
    子类用于重写默认 writeObject 方法的方法
  • void writeShort(int val)
    写入一个 16 位的 short 值
  • protected void writeStreamHeader()
    提供 writeStreamHeader 方法,
    这样子类可以将其自身的头部添加或预加到流中
  • void writeUnshared(Object obj)
    将“未共享”对象写入 ObjectOutputStream
  • void writeUTF(String str)
    以 UTF-8 修改版格式写入此 String 的基本数据

现在,本人来展示下部分API 的使用:



首先,本人给出一个用于存储粉丝信息的FanInfo:

package edu.youzg.about_io.about_file.core;

import java.io.Serializable;

public class FanInfo implements Serializable {
    private String name;
    //transient关键字 表示 某个成员变量不想序列化
    private transient int age;

    public FanInfo() {
    }

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

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

}

现在,本人来编写一个测试类:

package edu.youzg.about_io.about_file.core.Test;

import edu.youzg.about_io.about_file.core.FanInfo;

import java.io.*;

public class Test {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        FanInfo FanInfo3 = new FanInfo("朝菌", 1);
        FanInfo FanInfo1 = new FanInfo("南冥灵者", 500);
        FanInfo FanInfo2 = new FanInfo("大椿", 8000);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("FanInfo1.txt"));
        out.writeObject(FanInfo1);
        out.writeObject(FanInfo2);
        out.writeObject(FanInfo3);

        out.close();
    }

}

那么,现在,本人来展示下运行后的结果 以及 生成的文件的内容:



现在,本人来讲解下 反序列化流

ObjectInputStream 类:

(反序列化流):

概述

ObjectInputStream 用于恢复那些以前序列化的对象。
其他用途包括使用套接字流在主机之间传递对象,
或者用于编组和解组远程通信系统中的实参和形参。
ObjectInputStream 确保从流创建的图形中所有对象的类型与 Java 虚拟机中显示的类相匹配。
使用标准机制按需加载类。
只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。

本人先来展示下这个类的 构造方法

构造方法

  • protected ObjectInputStream()
    为完全重新实现 ObjectInputStream 的子类提供一种方式,
    让它不必分配仅由 ObjectInputStream 的实现使用的私有数据
  • ObjectInputStream(InputStream in)
    创建从指定 InputStream 读取的 ObjectInputStream

现在,本人来展示下这个类的常用API

常用API:

  • int available()
    返回可以不受阻塞地读取的字节数
  • void close()
    关闭输入流
  • void defaultReadObject()
    从此流读取当前类的非静态和非瞬态字段
  • protected boolean enableResolveObject(boolean enable)
    使流允许从该流读取的对象被替代
  • int read()
    读取数据字节
  • int read(byte[] buf, int off, int len)
    读入 byte 数组
  • boolean readBoolean()
    读取一个 boolean 值
  • byte readByte()
    读取一个 8 位的字节
  • char readChar()
    读取一个 16 位的 char 值
  • protected ObjectStreamClass readClassDescriptor()
    从序列化流读取类描述符
  • double readDouble()
    读取一个 64 位的 double 值
  • ObjectInputStream.GetField readFields()
    按名称从流中读取持久字段并使其可用
  • float readFloat()
    读取一个 32 位的 float 值
  • void readFully(byte[] buf)
    读取字节,同时阻塞直至读取所有字节
  • void readFully(byte[] buf, int off, int len)
    读取字节,同时阻塞直至读取所有字节
  • int readInt()
    读取一个 32 位的 int 值
  • long readLong()
    读取一个 64 位的 long 值
  • Object readObject()
    从 ObjectInputStream 读取对象
  • protected Object readObjectOverride()
    此方法由 ObjectOutputStream 的受信任子类调用,这些子类使用受保护的无参数构造方法构造 ObjectOutputStream
  • short readShort()
    读取一个 16 位的 short 值
  • protected void readStreamHeader()
    提供的 readStreamHeader 方法允许子类读取并验证它们自己的流头部
  • Object readUnshared()
    从 ObjectInputStream 读取“非共享”对象
  • int readUnsignedByte()
    读取一个无符号的 8 位字节
  • int readUnsignedShort()
    读取一个无符号的 16 位 short 值
  • String readUTF()
    读取 UTF-8 修改版格式的 String
  • void registerValidation(ObjectInputValidation obj, int prio)
    在返回图形前注册要验证的对象
  • protected Class<?> resolveClass(ObjectStreamClass desc)
    加载指定流类描述的本地等价类
  • protected Object resolveObject(Object obj)
    在反序列化期间,此方法允许 ObjectInputStream 的受信任子类使用一个对象替代另一个
  • protected Class<?> resolveProxyClass(String[] interfaces)
    返回一个代理类,该类实现在代理类描述符中命名的接口;
    子类可以实现此方法,以便从流及动态代理类的描述符中读取自定义数据,允许它们使用接口和代理类的替换加载机制
  • int skipBytes(int len)
    跳过字节
  • String readLine()
    已过时。 此方法不能正确地将字节转换为字符。请参见 DataInputStream 以获取详细信息和替代方法

那么,现在,本人来通过一个例子展示下部分API的使用:

现在,本人对上面代码生成的.txt文件来给出一个测试类:

package edu.youzg.about_io.about_file.core.Test;

import edu.youzg.about_io.about_file.core.FanInfo;

import java.io.*;

public class Test {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream objin = new ObjectInputStream(new FileInputStream("FanInfo1.txt"));
        Object obj = objin.readObject();
        FanInfo FanInfo= (FanInfo) obj;
        System.out.println(FanInfo.getName());
        obj = objin.readObject();
        FanInfo = (FanInfo) obj;
        System.out.println(FanInfo.getName());
        obj = objin.readObject();
        FanInfo = (FanInfo) obj;
        System.out.println(FanInfo.getAge());

        objin.close();
    }

}

现在,本人来展示下运行结果:

可以看到:
我们所存储的每个Fan对象的age成员,由于我们使用了transient关键字来修饰。
所以当我们读取的时候,输出的是0
(各类型被transient关键字修饰后,读取到的结果 和 我们读取未赋值的成员 所得到的结果一样)

那么,现在,本人修改下FanInfo类 —— 将name成员改为public修饰符修饰的
然后,再来运行下本人给出的测试类:

可以看到,出现了异常。
这是因为,我们存储该的对象信息 与 我们读取时的对象信息不同了。
其实,这个流检测的是该类的序列化版本号

其实,我们也可以通过自己设定个序列化版本号来克服这一点,
譬如,本人将FanInfo类改为如下:

package edu.youzg.about_io.about_file.core;

import java.io.Serializable;

public class FanInfo implements Serializable {
    private static final long serialVersionUID = -7602640005373026150L;

    private String name;
    private transient int age;

    public FanInfo() {
    }

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

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

}

那么,本人再运行下之前生成文件的代码,然后再将FanInfo类中的name成员改为public修饰符修饰的,再来运行下如下代码:

import edu.youzg.about_io.about_file.core.FanInfo;

import java.io.*;

public class Test {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream objin = new ObjectInputStream(new FileInputStream("FanInfo2.txt"));
        Object obj = objin.readObject();
        FanInfo FanInfo= (FanInfo) obj;
        System.out.println(FanInfo.getName());
        obj = objin.readObject();
        FanInfo = (FanInfo) obj;
        System.out.println(FanInfo.getName());
        obj = objin.readObject();
        FanInfo = (FanInfo) obj;
        System.out.println(FanInfo.getAge());
    }

}


可以看到,读取没有问题!

(本人 I/O流总集篇 博文链接:https:////www.cnblogs.com/codderYouzg/p/12418404.html

原文地址:https://www.cnblogs.com/codderYouzg/p/12418690.html

时间: 2024-11-13 02:46:35

详解 序列化流 与 反序列化流的相关文章

Java基础知识强化之IO流笔记65:序列化流 和 反序列化流

1. 什么是 序列化 和 反序列化 ?     序列化 (Serialization):将对象的状态信息转换为可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象.一般的格式是与平台无关的二进制流,可以将这种二进制流持久保存在磁盘上,也可以通过网络将这种二进制流传输到另一个网络结点.  反序列化(Anti Serialization ):是指把这种二进制流数据还原成对象. 2. 序列化流 和 反序列化

java中的序列化流和反序列化流

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px SimSun; color: #4e9072 } 序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输.  对象 -- 流数据(ObjectOutputStream) 反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象.流数据 -- 对象(ObjectInputStream) 序列化流和反序列化流不同于字节流 字符流 内存字节流,这些都是把字符串写入/读取文件,序列

wpf 客户端【JDAgent桌面助手】开发详解(三) 瀑布流效果实现与UI虚拟化优化大数据显示

目录区域: 业余开发的wpf 客户端终于完工了..晒晒截图 wpf 客户端[JDAgent桌面助手]开发详解-开篇 wpf 客户端[JDAgent桌面助手]详解(一)主窗口 圆形菜单... wpf 客户端[JDAgent桌面助手]开发详解(二)桌面宠物制作详解 因为前段时候有很多的事情 比较忙,自从上次写完博客之后很久没有更新了. 用WPF制作的京东桌面助手.这个作品是参加比赛的,自己花费了很多心思和时间在里面,最终的作品效果和比赛的结果还是令人满意的. 作品感觉不说很fashion,也足够细致

字符缓冲流,properties类,序列化流与反序列化流,打印流

1.字符缓冲流的写法与字节缓冲流类似,也是用字符缓冲对象嵌套字符读写对象.格式为: BufferedReader br=new BufferedReader(new FileReader(数据源)): BufferedWriter bw=new BufferedWriter(new FileWriter(目的地)): 2.BufferedReader有一个优势是可以读取一个文本行,它的方法是readLine(),这与FileReader相区别. 3.在IO操作时选用哪个对象,要看输入还是输出,文

IO流--序列化流与反序列化流

IO流--序列化流与反序列化流: 序列化流:把对象当做流一样写入到文本文件中 ObjectOutputSream(); 反序列化流:把文本文件中的流对象还原成对象ObjectInputSream(): 具体的使用: 1   创建java对象 实现序列化接口(Serializable): 序列化代码实现: 1 private void writer() throws IOException { 2 ObjectOutputStream oos = new ObjectOutputStream(ne

java -&gt;IO流_序列化流与反序列化流

序列化流与反序列化流 用于从流中读取对象的操作流 ObjectInputStream    称为 反序列化流 用于向流中写入对象的操作流 ObjectOutputStream   称为 序列化流(对象保存到文件中) l  特点:用于操作对象.可以将对象写入到文件中,也可以从文件中读取对象. 对象序列化流ObjectOutputStream ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream.可以使用 ObjectInputStream 读取

java--Properties、序列化流及反序列化流

一. Properties类 1. Properties类介绍 Properties 类表示了一个持久的属性集.Properties 可保存在流中或从流中加载.属性列表中每个键及其对应值都是一个字符串. 特点: (1).Hashtable的子类,map集合中的方法都可以用. (2).该集合没有泛型.键值都是字符串. (3).它是一个可以持久化的属性集.键值可以存储到集合中,也可以存储到持久化的设备(硬盘.U盘.光盘)上.键值的来源也可以是持久化的设备. (4).有和流技术相结合的方法. 2.常用

序列化流与反序列化流

序列化流与反序列化流 用于从流中读取对象的 操作流 ObjectInputStream    称为 反序列化流 用于向流中写入对象的操作流 ObjectOutputStream   称为 序列化流 特点:用于操作对象.可以将对象写入到文件中,也可以从文件中读取对象. 1 对象序列化流ObjectOutputStream 注意:只能将支持 java.io.Serializable 接口的对象写入流中 public static void method01() throws IOException{

序列化流与反序列化流,打印流

序列化流与反序列化流 ObjectOutputStream(序列化流) 将 Java 自定义对象写入 OutputStream.可以使用 ObjectInputStream(反序列化流) 读取对象.通过在流中使用文件可以实现对象的持久存储. ObjectOutputStream 序列化流   writeObject() 将指定的对象写入ObjectOutputStream 例: //创建对象 person per=new person("小红帽",18);//自定义类 //目的地 Fi