Maison > Java > Javacommencer > Sérialisation et désérialisation d'objets Java

Sérialisation et désérialisation d'objets Java

青灯夜游
Libérer: 2019-11-27 17:59:22
avant
2572 Les gens l'ont consulté

Sérialisation et désérialisation d'objets Java

Sérialisation et désérialisation d'objets

1) La sérialisation d'objet consiste à convertir l'objet Objet en séquence d'octets, sinon c'est ce qu'on appelle la désérialisation de l'objet.

2) Flux de sérialisation (ObjectOutputStream), qui est un flux filtré d'octets - méthode writeObject()

Flux de désérialisation (ObjectInputStream) - méthode readObject()

3) Interface sérialisable (Sérialisable)

L'objet doit implémenter l'interface de sérialisation pour être sérialisé, sinon une exception se produira.

Remarque : Cette interface n'a aucune méthode, c'est juste un [standard]

1. séquence la plus basique Le processus de sérialisation et de désérialisation

La sérialisation et la désérialisation sont toutes opérées sur des objets Object. Voici un cas simple pour démontrer le processus de sérialisation et de désérialisation d'objets.

1. Créez une nouvelle classe Étudiant (classe de test)

Remarque : Une classe qui implémente l'interface de sérialisation est requise pour effectuer les opérations de sérialisation ! !

@SuppressWarnings("serial")
public class Student implements Serializable{
    private String stuno;//id
    private String stuna;//姓名
    private int stuage;//年龄
    public String getStuno() {
        return stuno;
    }
    public void setStuno(String stuno) {
        this.stuno = stuno;
    }
    public String getStuna() {
        return stuna;
    }
    public void setStuna(String stuna) {
        this.stuna = stuna;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Student(String stuno, String stuna, int stuage) {
        super();
        this.stuno = stuno;
        this.stuna = stuna;
        this.stuage = stuage;
    }
    @Override
    public String toString() {
        return "Student [stuno=" + stuno + ", stuna=" + stuna + ", stuage=" + stuage + "]";
    }
    public int getStuage() {
        return stuage;
    }
    public void setStuage(int stuage) {
        this.stuage = stuage;
    }
}
Copier après la connexion

2. Sérialiser les instances de la classe Student dans des fichiers

Les étapes de base sont les suivantes :

1) Spécifier la sérialisation et enregistrer le fichier

2), construire la classe ObjectOutputStream

3), construire une classe Student

4), utiliser la méthode writeObject pour sérialiser

5 ), Utilisez la méthode close() pour fermer le flux

String file="demo/obj.dat";
        //对象的序列化
        ObjectOutputStream oos=new ObjectOutputStream(
                new FileOutputStream(file));
        //把Student对象保存起来,就是对象的序列化
        Student stu=new Student("01","mike",18);
        //使用writeObject方法序列化
        oos.writeObject(stu);
        oos.close();
Copier après la connexion

Résultats d'exécution : Vous pouvez voir que le fichier sérialisé de obj.dat a été généré dans le répertoire demo

3. Désérialisez le fichier et lisez l'objet de classe Student

Les étapes de base sont les suivantes :

1), spécifiez le fichier à désérialiser

2), Construisez la classe ObjectInputStream

3), utilisez la méthode readObject pour désérialiser

1), utilisez la méthode close pour fermer le flux

String file="demo/obj.dat";
        ObjectInputStream ois =new ObjectInputStream(
                new FileInputStream(file));
        //使用readObject()方法序列化
        Student stu=(Student)ois.readObject();//强制类型转换
        System.out.println(stu);
        ois.close();
Copier après la connexion

Résultats de fonctionnement :

Remarque : Lors de la désérialisation d'un fichier, les objets retirés par la méthode readObject sont de type Object par défaut et doivent être convertis en type correspondant.

2. Analyse du code source Transient et ArrayList

Dans le processus de programmation quotidien, parfois nous ne voulons pas tous les éléments d'une classe à sérialiser par le compilateur, que dois-je faire à ce moment-là ?

Java fournit un mot-clé transient pour modifier les éléments que nous ne souhaitons pas voir automatiquement sérialisés par la jvm. Expliquons brièvement ce mot-clé.

mot-clé transient : élément modifié par transient, cet élément ne sera pas sérialisé par jvm par défaut, mais vous pouvez compléter la sérialisation de cet élément par vous-même.

Remarque :

1) Dans la programmation future du réseau, s'il y a certains éléments qui n'ont pas besoin d'être transmis, vous pouvez utiliser la modification transitoire pour économiser du trafic oui ; Sérialisation efficace des éléments pour améliorer les performances.

2) Vous pouvez utiliser writeObject pour terminer vous-même la sérialisation de cet élément.

ArrayList est optimisé en utilisant cette méthode. Object[] elementData, le conteneur principal d'ArrayList, utilise une modification transitoire, mais la sérialisation du tableau elementData est implémentée dans writeObject lui-même. Seuls les éléments valides du tableau sont sérialisés. readObject est similaire.

--------------La façon de vous sérialiser- ----------------

Ajouter deux méthodes à la classe à sérialiser (Ces deux méthodes proviennent du code source d'ArrayList Deux méthodes spéciales extraites de  :

private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{
        s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化操作
        s.writeInt(stuage);//自己完成被transient修饰的元素的序列化
    }
    private void readObject(java.io.ObjectInputStream s) throws java.io.IOException,ClassNotFoundException{
        s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化操作
        this.stuage=s.readInt();//自己完成stuage的反序列化操作
    }
Copier après la connexion

Après avoir ajouté ces deux méthodes, même les éléments modifiés par transitoire peuvent être sérialisés et désérialisés car JVM utilisera automatiquement ces deux méthodes pour nous aider à terminer cette action. .

Il y a une autre question ici. Pourquoi devons-nous encore terminer la sérialisation et la désérialisation manuellement ?

Ce problème doit être analysé à partir du code source d'ArrayList :

Vous pouvez voir le Code source d'ArrayList Le but de l'auto-sérialisation : La couche inférieure d'ArrayList est un tableau. L'auto-sérialisation peut filtrer les éléments non valides dans le tableau et sérialiser uniquement les éléments valides dans le tableau, améliorant ainsi les performances .

Par conséquent, pendant le processus de programmation lui-même, nous pouvons terminer nous-mêmes la sérialisation si nécessaire pour améliorer les performances.

三、序列化中子父类构造函数问题

在类的序列化和反序列化中,如果存在子类和父类的关系时,序列化和反序列化的过程又是怎么样的呢?

这里我写一个测试类来测试子类和父类实现序列化和反序列化时构造函数的实现变化。

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String file="demo/foo.dat";
        ObjectOutputStream oos=new ObjectOutputStream(
                new FileOutputStream(file));
        Foo2 foo2 =new Foo2();
        oos.writeObject(foo2);
        oos.flush();
        oos.close();
    }

}
class Foo implements Serializable{
    public Foo(){
        System.out.println("foo");
    }
}
class Foo1 extends Foo{
    public Foo1(){
        System.out.println("foo1");
    }
    
}
class Foo2 extends Foo1{
    public Foo2(){
        System.out.println("foo2");
    }
}
Copier après la connexion

运行结果:这是序列化时递归调用了父类的构造函数

接来下看看反序列化时,是否递归调用父类的构造函数。

ObjectInputStream ois=new ObjectInputStream(
new FileInputStream(file));
Foo2 foo2=(Foo2)ois.readObject();
ois.close();
Copier après la connexion

运行结果:控制台没有任何输出。

那么这个结果是否证明反序列化过程中父类的构造函数就是始终不调用的呢?

然而不能证明!!

因为再看下面这个不同的测试例子:

class Bar {
    public Bar(){
        System.out.println("bar");
    }
}
class Bar1 extends Bar implements Serializable{
    public Bar1(){
        System.out.println("bar1");
    }
}
class Bar2 extends Bar1{
    public Bar2(){
        System.out.println("bar2");
    }
}
Copier après la connexion

我们用这个例子来测试序列化和反序列化。

序列化结果:

反序列化结果:没实现序列化接口的父类被显示调用构造函数

【反序列化时】,向上递归调用构造函数会从【可序列化的一级父类结束】。即谁实现了可序列化(包括继承实现的),谁的构造函数就不会调用。

总结:

1)父类实现了serializable接口,子类继承就可序列化。

子类在反序列化时,父类实现了序列化接口,则不会递归调用其构造函数。

2)父类未实现serializable接口,子类自行实现可序列化

子类在反序列化时,父类没有实现序列化接口,则会递归调用其构造函数。

本文来自 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!

Étiquettes associées:
source:cnblogs.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal