Pourquoi Java a-t-il des champs transitoires?

Réponses:

1673

Le transientmot-clé en Java est utilisé pour indiquer qu'un champ ne doit pas faire partie du processus de sérialisation (ce qui signifie enregistré, comme dans un fichier).

D'après les spécifications du langage Java, Java SE 7 Edition , Section 8.3.1.3. transientChamps :

Les variables peuvent être marquées transientpour indiquer qu'elles ne font pas partie de l'état persistant d'un objet.

Par exemple, vous pouvez avoir des champs qui sont dérivés d'autres champs et ne doivent être effectués que par programme, plutôt que de conserver l'état via la sérialisation.

Voici une GalleryImageclasse qui contient une image et une vignette dérivée de l'image:

class GalleryImage implements Serializable
{
    private Image image;
    private transient Image thumbnailImage;

    private void generateThumbnail()
    {
        // Generate thumbnail.
    }

    private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException
    {
        inputStream.defaultReadObject();
        generateThumbnail();
    }    
}

Dans cet exemple, le thumbnailImageest une image miniature générée en appelant la generateThumbnailméthode.

Le thumbnailImagechamp est marqué comme transient, donc seul l'original imageest sérialisé plutôt que de conserver l'image d'origine et l'image miniature. Cela signifie que moins de stockage serait nécessaire pour enregistrer l'objet sérialisé. (Bien sûr, cela peut être souhaitable ou non en fonction des exigences du système - ce n'est qu'un exemple.)

Au moment de la désérialisation, la readObjectméthode est appelée pour effectuer toutes les opérations nécessaires pour restaurer l'état de l'objet à l'état auquel la sérialisation s'est produite. Ici, la vignette doit être générée, la readObjectméthode est donc remplacée afin que la vignette soit générée en appelant la generateThumbnailméthode.

Pour plus d'informations, l'article Découvrez les secrets de l'API Java Serialization (qui était à l'origine disponible sur Sun Developer Network) comporte une section qui traite de l'utilisation et présente un scénario dans lequel le transientmot clé est utilisé pour empêcher la sérialisation de certains champs.

coobird
la source
221
Mais pourquoi est-ce un mot-clé et non une annotation @DoNotSerialize?
Elazar Leibovich
333
Je suppose que cela appartient à une époque où il n'y avait pas d'annotations en Java.
Peter Wippermann
46
Je trouve étrange que sérialisable soit interne à Java. Il peut être implémenté sous forme d'interface ou de classe abstraite qui oblige les utilisateurs à remplacer les méthodes de lecture et d'écriture.
caleb
7
@MJafar: readObject est généralement enchaîné dans des mécanismes de désérialisation et donc appelé automatiquement. De plus, dans de nombreux cas, vous n'avez pas besoin de la remplacer - l'implémentation par défaut fait l'affaire.
Mike Adler
13
@caleb probablement parce que traiter les formats binaires vous-même est incroyablement douloureux en Java en raison du manque d'entiers non signés.
droite le
435

Avant de comprendre le transientmot - clé, il faut comprendre le concept de sérialisation. Si le lecteur connaît la sérialisation, veuillez ignorer le premier point.

Qu'est-ce que la sérialisation?

La sérialisation est le processus qui rend l'état de l'objet persistant. Cela signifie que l'état de l'objet est converti en un flux d'octets à utiliser pour la persistance (par exemple, le stockage d'octets dans un fichier) ou le transfert (par exemple, l'envoi d'octets sur un réseau). De la même manière, nous pouvons utiliser la désérialisation pour ramener l'état de l'objet à partir d'octets. C'est l'un des concepts importants de la programmation Java car la sérialisation est principalement utilisée dans la programmation réseau. Les objets qui doivent être transmis via le réseau doivent être convertis en octets. À cette fin, chaque classe ou interface doit implémenter l' Serializableinterface. Il s'agit d'une interface de marqueur sans aucune méthode.

Maintenant, quel est le transientmot - clé et son but?

Par défaut, toutes les variables de l'objet sont converties dans un état persistant. Dans certains cas, vous souhaiterez peut-être éviter de persister certaines variables car vous n'avez pas besoin de les conserver. Vous pouvez donc déclarer ces variables comme transient. Si la variable est déclarée comme transient, elle ne sera pas persistante. C'est le but principal du transientmot - clé.

Je veux expliquer les deux points ci-dessus avec l'exemple suivant:

package javabeat.samples;

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

class NameStore implements Serializable{
    private String firstName;
    private transient String middleName;
    private String lastName;

    public NameStore (String fName, String mName, String lName){
        this.firstName = fName;
        this.middleName = mName;
        this.lastName = lName;
    }

    public String toString(){
        StringBuffer sb = new StringBuffer(40);
        sb.append("First Name : ");
        sb.append(this.firstName);
        sb.append("Middle Name : ");
        sb.append(this.middleName);
        sb.append("Last Name : ");
        sb.append(this.lastName);
        return sb.toString();
    }
}

public class TransientExample{
    public static void main(String args[]) throws Exception {
        NameStore nameStore = new NameStore("Steve", "Middle","Jobs");
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("nameStore"));
        // writing to object
        o.writeObject(nameStore);
        o.close();

        // reading from object
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("nameStore"));
        NameStore nameStore1 = (NameStore)in.readObject();
        System.out.println(nameStore1);
    }
}

Et la sortie sera la suivante:

First Name : Steve
Middle Name : null
Last Name : Jobs

Le deuxième prénom est déclaré comme transient, il ne sera donc pas stocké dans le stockage persistant.

La source

Rahul Saxena
la source
26
Cet exemple est tiré de ce code, vous pouvez le lire ici: javabeat.net/2009/02/what-is-transient-keyword-in-java
Krishna
11
Cette partie me semble étrange et peut-être déroutante: "Cela signifie que l'état de l'objet est converti en un flux d'octets et stocké dans un fichier ". Il me semble que la plupart du temps la sérialisation n'implique pas d'écrire dans un fichier (cas d'espèce: les exemples de mise en réseau qui suivent)
Garcia Hurtado
5
L'exemple est mauvais, car le deuxième prénom n'est clairement pas une propriété transitoire.
Raphael
1
@Raphael Pour moi, l'exemple est utile et explique au moins le concept. Pourriez-vous donner un meilleur exemple si vous êtes au courant?
Chaklader Asfak Arefe
@Yoda Nous pourrions avoir une référence à une NameFormatterhabitude de conduire toString(). Ou tout autre élément lié à la configuration, à l'affichage ou à la logique métier, ... par opposition aux données.
Raphael
84

Pour vous permettre de définir des variables que vous ne voulez pas sérialiser.

Dans un objet, vous pouvez avoir des informations que vous ne voulez pas sérialiser / persister (peut-être une référence à un objet d'usine parent), ou peut-être que cela n'a pas de sens de sérialiser. En les marquant comme «transitoires», le mécanisme de sérialisation ignorera ces champs.

Brian Agnew
la source
36

Ma petite contribution:

Qu'est-ce qu'un champ transitoire?
Fondamentalement, tout champ modifié avec le transientmot-clé est un champ transitoire.

Pourquoi les champs transitoires sont-ils nécessaires en Java?
Le transientmot clé vous donne un certain contrôle sur le processus de sérialisation et vous permet d'exclure certaines propriétés d'objet de ce processus. Le processus de sérialisation est utilisé pour conserver les objets Java, principalement afin que leurs états puissent être conservés lorsqu'ils sont transférés ou inactifs. Parfois, il est logique de ne pas sérialiser certains attributs d'un objet.

Quels champs devez-vous marquer comme transitoires?
Nous savons maintenant le but de latransientmots-clés et champs transitoires, il est important de savoir quels champs marquer comme transitoires. Les champs statiques ne sont pas sérialisés non plus, donc le mot-clé correspondant ferait aussi l'affaire. Mais cela pourrait ruiner la conception de votre classe; c'est là que le transientmot - clé vient à la rescousse. J'essaie de ne pas permettre la sérialisation des champs dont les valeurs peuvent être dérivées des autres, alors je les marque comme transitoires. Si vous avez un champ appelé interestdont la valeur peut être calculée à partir d'autres champs ( principal, rate& time), il n'est pas nécessaire de le sérialiser.

Un autre bon exemple est avec le nombre de mots d'article. Si vous enregistrez un article entier, il n'est vraiment pas nécessaire d'enregistrer le nombre de mots, car il peut être calculé lorsque l'article est "désérialisé". Ou pensez aux bûcherons;Logger les instances n'ont presque jamais besoin d'être sérialisées, elles peuvent donc devenir transitoires.

Shreyos Adikari
la source
63
Votre «simple phrase» n'est qu'une tautologie. Cela n'explique rien. Tu serais mieux sans ça.
Marquis de Lorne du
1
Ceci est une bonne explication où le terrain devrait êtretransient
Chaklader Asfak Arefe
1
le nombre de champs d'intérêt et de mots sont de bons exemples de champs transitoires.
Tarun
1
Un autre bon cas d'utilisation: si votre objet a des composants tels que des sockets et si vous souhaitez sérialiser, qu'advient-il du socket? Si persisterait, après la désérialisation, quelle serait la prise? Il est logique de rendre cet objet socket commetransient
Mohammed Siddiq
28

Une transientvariable est une variable qui ne peut pas être sérialisée.

Un exemple où cela peut être utile qui vient à l'esprit est, les variables qui n'ont de sens que dans le contexte d'une instance d'objet spécifique et qui deviennent invalides une fois que vous avez sérialisé et désérialisé l'objet. Dans ce cas, il est utile que ces variables deviennent à la nullplace afin que vous puissiez les réinitialiser avec des données utiles en cas de besoin.

Adrian Grigore
la source
oui, quelque chose comme les membres du champ "mot de passe ou crediCardPin" d'une classe.
Mateen
17

transientest utilisé pour indiquer qu'un champ de classe n'a pas besoin d'être sérialisé. Le meilleur exemple est probablement un Threadchamp. Il n'y a généralement aucune raison de sérialiser un Thread, car son état est très «spécifique au flux».

Andrei Ciobanu
la source
Corrigez-moi si je me trompe, mais le fil n'est pas sérialisable, il sera donc ignoré de toute façon?
TFennis
3
@TFennis: Si une classe sérialisable fait Aréférence à une classe non sérialisable B(comme Threaddans votre exemple), alors Adoit soit marquer la référence comme transientXOR doit remplacer le processus de sérialisation par défaut afin de faire quelque chose de raisonnable avec BXOR supposer que seules les sous-classes sérialisables de Bsont réellement référencées (donc la sous-classe réelle doit prendre soin de son "mauvais" parent B) XOR accepte que la sérialisation échoue. Dans un seul cas (marqué comme transitoire) Best automatiquement et silencieusement ignoré.
AH
3
@TFennis Non, cela provoquera une exception.
Marquis de Lorne du
1
@AH: Pourquoi XOR? Je pense que le code qui a fait n'importe quelle combinaison de ces choses fonctionnerait, et certaines combinaisons pourraient être utiles (par exemple, remplacer le processus de sérialisation par défaut peut être utile même si seules les sous-classes sérialisables de B sont référencées, et vice versa).
supercat
15

Les systèmes de sérialisation autres que Java natif peuvent également utiliser ce modificateur. Hibernate, par exemple, ne conservera pas les champs marqués avec @Transient ou le modificateur transitoire . La terre cuite respecte également ce modificateur.

Je crois que la signification figurative du modificateur est "ce champ est destiné à un usage en mémoire uniquement. Ne persistez pas et ne le déplacez pas en dehors de cette machine virtuelle particulière. Son non portable". c'est-à-dire que vous ne pouvez pas compter sur sa valeur dans un autre espace mémoire VM. Tout comme volatile signifie que vous ne pouvez pas vous fier à certaines sémantiques de mémoire et de thread.

DragonFax
la source
14
Je pense que transientce ne serait pas un mot-clé s'il était conçu en ce moment. Ils utiliseraient probablement une annotation.
Joachim Sauer
9

Parce que toutes les variables ne sont pas de nature sérialisable

Silfverstrom
la source
42
Veuillez fournir plus d'informations lorsque vous donnez une réponse.
Danny Gloudemans
7

Avant de répondre à cette question, je dois vous expliquer la SÉRIALISATION , car si vous comprenez ce que signifie la sérialisation en informatique scientifique, vous pouvez facilement comprendre ce mot-clé.

Sérialisation Lorsqu'un objet est transféré via le réseau / enregistré sur un support physique (fichier, ...), l'objet doit être "sérialisé". La sérialisation convertit la série d'objets d'état d'octet. Ces octets sont envoyés sur le réseau / enregistrés et l'objet est recréé à partir de ces octets.
Exemple

public class Foo implements Serializable 
{
 private String attr1;
 private String attr2;
 ...
}

Maintenant, SI VOUS VOULEZ NE PAS TRANSFÉRER / ENREGISTRER le champ de cet objet SO , vous pouvez utiliser le mot-clé transient

private transient attr2;

Exemple

BERGUIGA Mohamed Amine
la source
6

Il est nécessaire lorsque vous ne souhaitez pas partager certaines données sensibles associées à la sérialisation.

setzamora
la source
7
Il existe des cas d'utilisation autres que des données sensibles dans lesquels vous ne souhaitez peut-être pas sérialiser un champ. Par exemple, vous ne voudrez probablement jamais sérialiser un Thread(crédit à @AH par exemple), auquel cas vous le marquerez comme transitoire. Cependant, un thread n'est pas une donnée sensible en soi, il n'est tout simplement pas logique de le sérialiser (et il n'est pas sérialisable).
glen3b
1
@ glen3b Ce cas n'est pas exclu par cette réponse. C'est certainement nécessaire dans l'état actuel de l'affiche mentionnée.
Marquis de Lorne
3

Selon la signification transitoire de Google == qui ne dure que peu de temps; transitoire.

Maintenant, si vous voulez rendre quelque chose de transitoire en java, utilisez un mot-clé transitoire.

Q: où utiliser les transitoires?

R: Généralement, en Java, nous pouvons enregistrer des données dans des fichiers en les acquérant dans des variables et en écrivant ces variables dans des fichiers, ce processus est connu sous le nom de sérialisation. Maintenant, si nous voulons éviter que des données variables soient écrites dans un fichier, nous rendrons cette variable transitoire.

transient int result=10;

Remarque: les variables transitoires ne peuvent pas être locales.

Mateen
la source
0

Autrement dit, le mot-clé java transitoire protège les champs de la série Serialize en tant que contre-parties des champs non transitoires.

Dans cet extrait de code, notre classe abstraite BaseJob implémente l'interface Serializable, nous étendons de BaseJob mais nous n'avons pas besoin de sérialiser les sources de données distantes et locales; sérialiser uniquement les champs organizationName et isSynced.

public abstract class BaseJob implements Serializable{
   public void ShouldRetryRun(){}
}

public class SyncOrganizationJob extends BaseJob {

   public String organizationName;
   public Boolean isSynced

   @Inject transient RemoteDataSource remoteDataSource;
   @Inject transient LocalDaoSource localDataSource;

   public SyncOrganizationJob(String organizationName) {
     super(new 
         Params(BACKGROUND).groupBy(GROUP).requireNetwork().persist());

      this.organizationName = organizationName;
      this.isSynced=isSynced;

   }
}
nyulan
la source
0

Exemple de code simplifié pour mot-clé transitoire.

import java.io.*;

class NameStore implements Serializable {
    private String firstName, lastName;
    private transient String fullName;

    public NameStore (String fName, String lName){
        this.firstName = fName;
        this.lastName = lName;
        buildFullName();
    }

    private void buildFullName() {
        // assume building fullName is compuational/memory intensive!
        this.fullName = this.firstName + " " + this.lastName;
    }

    public String toString(){
        return "First Name : " + this.firstName
            + "\nLast Name : " + this.lastName
            + "\nFull Name : " + this.fullName;
    }

    private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException
    {
        inputStream.defaultReadObject();
        buildFullName();
    }
}

public class TransientExample{
    public static void main(String args[]) throws Exception {
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("ns"));
        o.writeObject(new NameStore("Steve", "Jobs"));
        o.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("ns"));
        NameStore ns = (NameStore)in.readObject();
        System.out.println(ns);
    }
}
Habeeb Perwad
la source
0

Un champ qui est déclaré avec un modificateur transitoire ne participera pas au processus sérialisé. Lorsqu'un objet est sérialisé (enregistré dans n'importe quel état), les valeurs de ses champs transitoires sont ignorées dans la représentation série, tandis que le champ autre que les champs transitoires participera au processus de sérialisation. C'est le but principal du mot-clé transitoire.

Vishal Sheth
la source