Java-序列化

2021-03-22 07:27

阅读:586

标签:static   dex   shu   修改   使用   vat   rgs   示例   final   

序列化的含义和意义

序列化指将Java对象转换成字节序列, 这些字节序列可以保存在磁盘上, 或者进行网络传输。反序列化即指将序列化后的字节序列重新恢复成对象。序列化机制使得对象可以脱离程序的运行而独立存在。

一个Java对象要能序列化,必须实现一个特殊的java.io.Serializable接口,这个接口不包含任何方法或成员变量,只是一个标记。

?

序列化

序列化通过ObjectOutputStream来实现,它可以把一个Java对象写入字节流。

当序列化一个对象到文件时, 按照 Java 的标准约定是给文件一个 .ser 扩展名.

?

示例:

import java.io.*;

public class SerializableDemo {
    public static void main(String[] args) throws Exception {
        File file = new File("E:\\person.ser");
        FileOutputStream out = new FileOutputStream(file);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);

        Person person = new Person("王大锤", 25);
        objectOutputStream.writeObject(person);
        System.out.println("写入的对象:" + person);
    }

    private static void readObj() throws Exception{
        File file = new File("E:\\person.ser");
        FileInputStream in = new FileInputStream(file);
        ObjectInputStream objectInputStream = new ObjectInputStream(in);

        Person person = (Person)objectInputStream.readObject();
        System.out.println("读取的对象:" + person);
    }

}

class Person implements Serializable{
    private String name;
    private int age;

    public Person(String name, int age) {
        System.out.println("Person‘s constructor");
        this.name = name;
        this.age = age;
    }

    //...省略getter、setter、toString
}

程序输出:

Person‘s constructor
写入的对象:Person{name=‘王大锤‘, age=25}

?

反序列化

反序列化使用ObjectInputStream对象,它可以从字节流中读取一个Java对象。若反序列化时要使用readObject()读出多个对象,注意要与写入的顺序一致。

示例:

import java.io.*;

public class SerializableDemo {
    public static void main(String[] args) throws Exception {
        File file = new File("E:\\person.ser");
        FileInputStream in = new FileInputStream(file);
        ObjectInputStream objectInputStream = new ObjectInputStream(in);

        Person person = (Person)objectInputStream.readObject();
        System.out.println("读取的对象:" + person);
    }
}

程序输出:

读取的对象:Person{name=‘王大锤‘, age=25}

可以看到反序列化时,Person的构造器并没有执行。反序列化时,是由JVM直接构造出Java对象,不调用构造方法,构造方法内部的代码,在反序列化时根本不可能执行

?

在反序列化时readObject()可能抛出的异常有

  • ClassNotFoundException:没有找到对应的Class;
  • InvalidClassException:Class不匹配。

抛出ClassNotFoundException的情况:一台电脑上的Java程序把一个Java对象序列化以后,通过网络传给另一台电脑上的另一个Java程序,但是这台电脑的Java程序并没有定义该类,所以无法反序列化,抛出该异常。

抛出InvalidClassException的情况:例如序列化的Person对象定义了一个int类型的age字段,但是反序列化时,Person类定义的age字段被改成了long类型,所以导致class不兼容。为了避免这种不兼容,Java的序列化允许class定义一个特殊的serialVersionUID静态变量,用于标识Java类的序列化“版本”。如果增加或修改了字段,可以改变serialVersionUID的值,这样就能自动阻止不匹配的class版本。

IDEA自动生成serialVersionUID静态变量的方法:IDEA自动生成serialVersionUID

?

序列化的特殊情况

  • 当要序列化的对象中包含其他引用类型变量的引用时,该变量对应的类也要实现Serializable接口
  • 对同一个对象多次序列化,只有第一次序列化时JVM才会将对象转换为字节序列,之后的序列化只是直接输出一个序列化编号。且反序列化时多次使用readObject()读出的是同一个对象。

?

示例:

示例中的Person类同上。新增了一个ID类:

package stream.serializable;

import java.io.Serializable;

public class ID implements Serializable {
    private static final long serialVersionUID = -5829455553074732547L;
    private int number;
    private Person person;

    //...省略getter、setter、toString
}

?

创建一个Person对象person和一个ID对象id,id中的Person指向person。将person和id序列化。再反序列,可看到readId.getPerson()==readPerson返回true。

public static void main(String[] args) throws Exception {
    File file = new File("E:\\id.ser");
        FileOutputStream out = new FileOutputStream(file);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);

        ID id = new ID();
        Person person = new Person("王大锤", 30);
        id.setNumber(1);
        id.setPerson(person);
        objectOutputStream.writeObject(id);
        objectOutputStream.writeObject(person);

        FileInputStream in = new FileInputStream(file);
        ObjectInputStream objectInputStream = new ObjectInputStream(in);
        ID readId = (ID) objectInputStream.readObject();
        Person readPerson = (Person) objectInputStream.readObject();

        System.out.println(readId);
        System.out.println(readPerson);
        System.out.print("readId.getPerson()==readPerson:");
        System.out.print(readId.getPerson()==readPerson);
}

?

参考

廖雪峰Java教程-序列化

菜鸟教程

《疯狂Java讲义 第4版》

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

?

Java-序列化

标签:static   dex   shu   修改   使用   vat   rgs   示例   final   

原文地址:https://www.cnblogs.com/bxiaoo/p/13888517.html


评论


亲,登录后才可以留言!