Java-对象序列化流/返序列化流

概述

对象序列化:就是将对象写入到磁盘中,或者在网络中传输对象。
这种机制就是使用一个字节序列,这个序列包含对象的信息:对象类型,对象数据,对象中存储的属性等等。字节序列写入到文件当中,相当于在文件中长久的保存一个对象的信息。
反序列化当然就是将对象的信息从文件中取出来,重构对象。
对象序列化流和反序列化流分别是:

  • ObjectOutputStream(对象序列化流)
  • ObjectInputStream(对象反序列化流)

对象序列化流ObjectOutputStream

序列化流继承自抽象类输出流在这里插入图片描述
在这里插入图片描述
ObjectOutputStream将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象

  • 构造方法
public ObjectOutputStream(OutputStream out)

创建一个写入指定的OutputStream的ObjectOutputStream。 该构造函数将序列化流头写入底层流; 调用者可能希望立即刷新流,以确保在读取头部时接收ObjectInputStreams的构造函数不会阻塞。
参数类型是OutputStream,所以我们可以用FileOutputStream之类进行传参。
异常
IOException - 如果在写入流标题时发生I / O错误
SecurityException - 如果不可信子类非法覆盖安全敏感方法
NullPointerException - 如果 out是 null

  • 写对象的方法:
public final void writeObject(Object obj)

将指定的对象写入ObjectOutputStream。 写入对象的类,类的签名以及类的非瞬态和非静态字段的值以及其所有超类型。 可以使用writeObject和readObject方法覆盖类的默认序列化。 由该对象引用的对象被传递性地写入,以便可以通过ObjectInputStream重构对象的完整等价图。

  • 使用举例1(String类写入)
 ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D://filetest//writed.txt"));
        String i=new String("wwww");
        oos.writeObject(i);
        oos.close();

使用举例2(自定义类写入)

import java.io.Serializable;

public class Student  implements Serializable  {
    String ID;
    String name;

    public Student() {
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "ID='" + ID + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}
import java.io.*;

public class IoDemo {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D://filetest//writed.txt"));
        Student stu=new Student("12","王民");
        oos.writeObject(stu);
        oos.close();
    }
    }

public class Student implements Serializable:这里最重要的是如果是你要序列化的类,那个类要implements Serializable接口否则会抛异常。这个结构没有方法,只需要实现就行。

  • Serializable 接口
    public interface Serializable类的序列化由实现java.io.Serializable接口的类启用。 不实现此接口的类将不会使任何状态序列化或反序列化。 可序列化类的所有子类型都是可序列化的。 序列化接口没有方法或字段,仅用于标识可串行化的语义。

反序列化流ObjectInputStream

ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D://filetest//writed.txt"));
        Object obj = ois.readObject();
        Student stu1=(Student)obj;//向下转型
        System.out.println(stu1.toString());
        ois.close();

InvalidClassException

这块的标题是一个异常,当然要说一下什么时候遇到这个异常。

public class InvalidClassException extends ObjectStreamException当序列化运行时检测到类中的以下问题之一时抛出:

  • 类的串行版本与从流中读取的类描述符的类型不匹配 (与当初write的类不同,此时类可能被修改
  • 该类包含未知的数据类型
  • 该类没有可访问的无参数构造函数

基于上面的问题,只要write之后类被修改了,那么就会抛出这个异常无法读取。
于是我们有了下面两个问题:

  • 1:如果出现问题该如何让解决?(例如:类被修改了此时还想读)
    这个问题我们先看我们的异常样子
    Exception in thread “main” java.io.InvalidClassException: Student;local class incompatible:
    stream classdesc serialVersionUID = 5583702560695495207,
    local class serialVersionUID = -6022075613783040060
    这里我们看到问题时我们修改类前后类的序列化UID不同

我们在来看Serializable接口文档里面直接给出我们的解决方案:
如果可序列化类没有显式声明serialVersionUID,则序列化运行时将根据Java(TM)对象序列化规范中所述的类的各个方面计算该类的默认serialVersionUID值。 但是, 强烈建议所有可序列化的类都明确声明serialVersionUID值,因为默认的serialVersionUID计算对类详细信息非常敏感,这可能会因编译器实现而异,因此可能会在反InvalidClassException化期间导致InvalidClassException的InvalidClassException。 因此,为了保证不同Java编译器实现之间的一致的serialVersionUID值,一个可序列化的类必须声明一个显式的serialVersionUID值。 还强烈建议,显式的serialVersionUID声明在可能的情况下使用private修饰符,因为这种声明仅适用于立即声明的类 - serialVersionUID字段作为继承成员无效。 数组类不能声明一个显式的serialVersionUID,所以它们总是具有默认的计算值,但是对于数组类,放弃了匹配serialVersionUID值的要求。

哈,这里解决方案就出来了,声明一个显式的serialVersionUID值,使用private修饰符。

  • 2:如果类中某个成员变量不想被序列化怎么做?(例如:Student类里面的ID不想被序列化)
    使用transient修饰变量 例如:transient String ID;
import java.io.Serializable;

public class Student  implements Serializable  {
    transient String  ID;
    String name;
    private static final long serialVersionUID=42L;


    public Student() {
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "ID='" + ID + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}
import java.io.*;

public class IoDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D://filetest//writed.txt"));
        Student stu=new Student("12","王民");
        oos.writeObject(stu);
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D://filetest//writed.txt"));
        Object obj = ois.readObject();
        Student stu1=(Student)obj;//向下转型
        System.out.println(stu1.toString());
        ois.close();
    }
    }
发布了43 篇原创文章 · 获赞 12 · 访问量 1406

猜你喜欢

转载自blog.csdn.net/qq_42411214/article/details/104437662