Maison >Java >JavaBase >Parlez de la sérialisation et de la désérialisation dans les objets Java

Parlez de la sérialisation et de la désérialisation dans les objets Java

青灯夜游
青灯夜游avant
2020-07-03 10:03:592474parcourir

Parlez de la sérialisation et de la désérialisation dans les objets Java

1. Le concept de sérialisation et de désérialisation

Convertir l'objet en Le processus de la séquence d'octets est appelée sérialisation des objets .

Le processus de restauration d'une séquence d'octets dans un objet est appelé désérialisation de l'objet .

La sérialisation des objets a deux utilisations principales :

1) Enregistrez de manière permanente la séquence d'octets de l'objet sur le disque dur, généralement dans un fichier

2) Transférez la séquence d'octets de l'objet sur le réseau.

Dans de nombreuses applications, il est nécessaire de sérialiser certains objets afin qu'ils puissent sortir de l'espace mémoire et être stockés sur le disque dur physique pour un stockage à long terme. Par exemple, le plus courant est l'objet Session sur le serveur Web. Lorsque 100 000 utilisateurs y accèdent simultanément, il peut y avoir 100 000 objets Session, ce qui peut être trop pour la mémoire, de sorte que le conteneur Web sérialise certaines sessions sur le disque dur. disque d'abord, et ainsi de suite. Lorsque vous souhaitez l'utiliser, restaurez l'objet enregistré sur le disque dur dans la mémoire.

Lorsque deux processus communiquent à distance, ils peuvent s'envoyer différents types de données. Quel que soit le type de données, elles sont transmises sur le réseau sous la forme d'une séquence binaire. L'expéditeur doit convertir cet objet Java en une séquence d'octets avant de pouvoir le transmettre sur le réseau ; le destinataire doit restaurer la séquence d'octets en un objet Java.

2. API de sérialisation dans la bibliothèque de classes JDK

java.io.ObjectOutputStream représente le flux de sortie de l'objet et son writeObject(Object obj ) La méthode peut sérialiser l'objet obj spécifié par le paramètre et écrire la séquence d'octets résultante dans un flux de sortie cible.

java.io.ObjectInputStream représente un flux d'entrée d'objet. Sa méthode readObject() lit une séquence d'octets à partir d'un flux d'entrée source, les désérialise en un objet et le renvoie.
Seuls les objets des classes qui implémentent les interfaces Serialisable et Externalisable peuvent être sérialisés. L'interface externalisable hérite de Interface sérialisable. Les classes qui implémentent l'interface externalisable contrôlent entièrement le comportement de sérialisation par elles-mêmes, tandis que les classes qui implémentent uniquement l'interface sérialisable peuvent le faire. Utilisez la méthode de sérialisation par défaut.
 La sérialisation d'objets comprend les étapes suivantes :
 1) Créer un flux de sortie d'objet, qui peut envelopper un flux de sortie cible d'autres types, comme un flux de sortie de fichier
 2) Via writeObject() du ; flux de sortie de l'objet La méthode écrit l'objet.

Les étapes de désérialisation d'objet sont les suivantes :
1) Créer un flux d'entrée d'objet, qui peut envelopper un autre type de flux d'entrée source, tel qu'un flux d'entrée de fichier
2) Passer ; le flux d'entrée de l'objet La méthode readObject() lit l'objet.

Exemples de sérialisation et de désérialisation d'objets :

Définir une classe Person et implémenter l'interface Serialisable

import java.io.Serializable;

/**
 * <p>ClassName: Person<p>
 * <p>Description:测试对象序列化和反序列化<p>
 * @author xudp
 * @version 1.0 V
 * @createTime 2014-6-9 下午02:33:25
 */
public class Person implements Serializable {

    /**
     * 序列化ID
     */
    private static final long serialVersionUID = -5809782578272943999L;
    private int age;
    private String name;
    private String sex;

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public String getSex() {
        return sex;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    public void setSex(String sex) {
        this.sex = sex;
    }
}

 

Sérialisation et désérialiser les objets de la classe Person

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.MessageFormat;

/**
 * <p>ClassName: TestObjSerializeAndDeserialize<p>
 * <p>Description: 测试对象的序列化和反序列<p>
 * @author xudp
 * @version 1.0 V
 * @createTime 2014-6-9 下午03:17:25
 */
public class TestObjSerializeAndDeserialize {

    public static void main(String[] args) throws Exception {
        SerializePerson();//序列化Person对象
        Person p = DeserializePerson();//反序列Perons对象
        System.out.println(MessageFormat.format("name={0},age={1},sex={2}",
                                                 p.getName(), p.getAge(), p.getSex()));
    }

    /**
     * MethodName: SerializePerson
     * Description: 序列化Person对象
     * @author xudp
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static void SerializePerson() throws FileNotFoundException,
            IOException {
        Person person = new Person();
        person.setName("gacl");
        person.setAge(25);
        person.setSex("男");
        // ObjectOutputStream 对象输出流,将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
                new File("E:/Person.txt")));
        oo.writeObject(person);
        System.out.println("Person对象序列化成功!");
        oo.close();
    }

    /**
     * MethodName: DeserializePerson
     * Description: 反序列Perons对象
     * @author xudp
     * @return
     * @throws Exception
     * @throws IOException
     */
    private static Person DeserializePerson() throws Exception, IOException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                new File("E:/Person.txt")));
        Person person = (Person) ois.readObject();
        System.out.println("Person对象反序列化成功!");
        return person;
    }

}

Les résultats de l'exécution du code sont les suivants :

Parlez de la sérialisation et de la désérialisation dans les objets Java

Après avoir sérialisé avec succès Person A Person Le fichier .txt est généré sur le lecteur E, et la Personne désérialisée génère un objet Person après avoir lu le Person.txt du lecteur E

3. Le rôle de SerialVersionUID

serialVersionUID : signifie littéralement le numéro de version sérialisé. Chaque classe qui implémente l'interface Serialisable a une variable statique représentant l'identifiant de version sérialisée

private static final long serialVersionUID
<.>Si SerialVersionUID n'est pas ajouté à la classe qui implémente l'interface Serialisable, l'invite d'avertissement suivante apparaîtra


Parlez de la sérialisation et de la désérialisation dans les objets JavaCliquez avec la souris Une boîte de dialogue pour générer SerialVersionUID apparaîtra, comme indiqué ci-dessous :

Parlez de la sérialisation et de la désérialisation dans les objets JavaIl existe deux façons de générer SerialVersionUID :


Utilisez

this Le SerialVersionUID généré par ce La méthode est 1L, par exemple :

private static final long serialVersionUID = 1L;
Le SerialVersionUID généré par est basé sur le nom de la classe, le nom de l'interface, la méthode et l'attribut, etc., par exemple :

private static final long serialVersionUID = 4603642343377807741L;
Après l'ajout l'avertissement n'apparaîtra pas, comme indiqué ci-dessous :


Parlez de la sérialisation et de la désérialisation dans les objets JavaAprès tant de choses, à quoi sert le serialVersionUID (numéro de version sérialisé) ? l'exemple suivant pour illustrer le rôle de serialVersionUID. Regardez le code suivant :

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class TestSerialversionUID {

    public static void main(String[] args) throws Exception {
        SerializeCustomer();// 序列化Customer对象
        Customer customer = DeserializeCustomer();// 反序列Customer对象
        System.out.println(customer);
    }

    /**
     * MethodName: SerializeCustomer
     * Description: 序列化Customer对象
     * @author xudp
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static void SerializeCustomer() throws FileNotFoundException,
            IOException {
        Customer customer = new Customer("gacl",25);
        // ObjectOutputStream 对象输出流
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
                new File("E:/Customer.txt")));
        oo.writeObject(customer);
        System.out.println("Customer对象序列化成功!");
        oo.close();
    }

    /**
     * MethodName: DeserializeCustomer
     * Description: 反序列Customer对象
     * @author xudp
     * @return
     * @throws Exception
     * @throws IOException
     */
    private static Customer DeserializeCustomer() throws Exception, IOException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                new File("E:/Customer.txt")));
        Customer customer = (Customer) ois.readObject();
        System.out.println("Customer对象反序列化成功!");
        return customer;
    }
}

/**
 * <p>ClassName: Customer</p><p>
 * </p><p>Description: Customer实现了Serializable接口,可以被序列化</p><p>
 * @author xudp
 * @version 1.0 V
 * @createTime 2014-6-9 下午04:20:17
 */
class Customer implements Serializable {
    //Customer类中没有定义serialVersionUID
    private String name;
    private int age;

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

    /*
     * @MethodName toString
     * @Description 重写Object类的toString()方法
     * @author xudp
     * @return string
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "name=" + name + ", age=" + age;
    }
}</p>

Résultat d'exécution :

.

Parlez de la sérialisation et de la désérialisation dans les objets JavaParlez de la sérialisation et de la désérialisation dans les objets Java

序列化和反序列化都成功了。

下面我们修改一下Customer类,添加多一个sex属性,如下:

class Customer implements Serializable {
    //Customer类中没有定义serialVersionUID
    private String name;
    private int age;

    //新添加的sex属性
    private String sex;

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

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

    /*
     * @MethodName toString
     * @Description 重写Object类的toString()方法
     * @author xudp
     * @return string
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "name=" + name + ", age=" + age;
    }
}

然后执行反序列操作,此时就会抛出如下的异常信息:

1 Exception in thread "main" java.io.InvalidClassException: Customer; 
2 local class incompatible: 
3 stream classdesc serialVersionUID = -88175599799432325, 
4 local class serialVersionUID = -5182532647273106745

意思就是说,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID。在TestSerialversionUID例子中,没有指定Customer类的serialVersionUID的,那么java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件 多一个空格,得到的UID就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,添加了一个字段后,由于没有显指定 serialVersionUID,编译器又为我们生成了一个UID,当然和前面保存在文件中的那个不会一样了,于是就出现了2个序列化版本号不一致的错误。因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法或者属性可以用。

下面继续修改Customer类,给Customer指定一个serialVersionUID,修改后的代码如下:

class Customer implements Serializable {
    /**
     * Customer类中定义的serialVersionUID(序列化版本号)
     */
    private static final long serialVersionUID = -5182532647273106745L;
    private String name;
    private int age;

    //新添加的sex属性
    //private String sex;

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

    /*public Customer(String name, int age,String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }*/

    /*
     * @MethodName toString
     * @Description 重写Object类的toString()方法
     * @author xudp
     * @return string
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "name=" + name + ", age=" + age;
    }
}

重新执行序列化操作,将Customer对象序列化到本地硬盘的Customer.txt文件存储,然后修改Customer类,添加sex属性,修改后的Customer类代码如下:

class Customer implements Serializable {
    /**
     * Customer类中定义的serialVersionUID(序列化版本号)
     */
    private static final long serialVersionUID = -5182532647273106745L;
    private String name;
    private int age;

    //新添加的sex属性
    private String sex;

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

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

    /*
     * @MethodName toString
     * @Description 重写Object类的toString()方法
     * @author xudp
     * @return string
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "name=" + name + ", age=" + age;
    }
}

执行反序列操作,这次就可以反序列成功了,如下所示:

Parlez de la sérialisation et de la désérialisation dans les objets Java

四、serialVersionUID的取值

serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。

类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值

显式地定义serialVersionUID有两种用途:

1、 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;

2、 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

推荐学习:Java视频教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer