Warum hat Java Übergangsfelder?


Antworten:


1673

Das transientSchlüsselwort in Java wird verwendet, um anzugeben, dass ein Feld nicht Teil des Serialisierungsprozesses sein soll (dh wie in einer Datei gespeichert).

Aus der Java-Sprachspezifikation, Java SE 7 Edition , Abschnitt 8.3.1.3. transientFelder :

Variablen können markiert werden, transientum anzuzeigen, dass sie nicht Teil des dauerhaften Zustands eines Objekts sind.

Beispielsweise können Felder vorhanden sein, die von anderen Feldern abgeleitet sind und nur programmgesteuert ausgeführt werden sollten, anstatt den Status über die Serialisierung beizubehalten.

Hier ist eine GalleryImageKlasse, die ein Bild und eine Miniaturansicht enthält, die vom Bild abgeleitet sind:

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();
    }    
}

In diesem Beispiel thumbnailImagehandelt es sich um ein Miniaturbild, das durch Aufrufen der generateThumbnailMethode generiert wird .

Das thumbnailImageFeld ist als markiert transient, sodass nur das Original imageserialisiert wird, anstatt sowohl das Originalbild als auch das Miniaturbild beizubehalten. Dies bedeutet, dass weniger Speicher benötigt wird, um das serialisierte Objekt zu speichern. (Natürlich kann dies abhängig von den Anforderungen des Systems wünschenswert sein oder auch nicht - dies ist nur ein Beispiel.)

Zum Zeitpunkt der Deserialisierung wird die readObjectMethode aufgerufen, um alle Operationen auszuführen, die erforderlich sind, um den Status des Objekts auf den Status zurückzusetzen, in dem die Serialisierung stattgefunden hat. Hier muss die Miniaturansicht generiert werden, damit die readObjectMethode überschrieben wird, damit die Miniaturansicht durch Aufrufen der generateThumbnailMethode generiert wird .

Weitere Informationen finden Sie im Artikel Entdecken Sie die Geheimnisse des Java Serialization API- Artikels (der ursprünglich im Sun Developer Network verfügbar war). In diesem Abschnitt wird die Verwendung erläutert und ein Szenario vorgestellt, in dem das transientSchlüsselwort verwendet wird, um die Serialisierung bestimmter Felder zu verhindern.


221
Aber warum ist es ein Schlüsselwort und keine Anmerkung @DoNotSerialize?
Elazar Leibovich

333
Ich denke, dies gehört zu einer Zeit, als es in Java keine Anmerkungen gab.
Peter Wippermann

46
Ich finde es seltsam, dass serialisierbar in Java intern ist. Es kann als Schnittstelle oder abstrakte Klasse implementiert werden, bei der Benutzer die Lese- und Schreibmethoden überschreiben müssen.
Caleb

7
@MJafar: readObject wird normalerweise in Deserialisierungsmechanismen verkettet und daher automatisch aufgerufen. Darüber hinaus müssen Sie es in vielen Fällen nicht überschreiben - die Standardimplementierung erledigt den Trick.
Mike Adler

13
@caleb wahrscheinlich, weil der Umgang mit Binärformaten in Java aufgrund des Fehlens von Ganzzahlen ohne Vorzeichen unglaublich schmerzhaft ist.
Rechtsfalte

435

Bevor man das transientSchlüsselwort versteht, muss man das Konzept der Serialisierung verstehen. Wenn der Leser etwas über Serialisierung weiß, überspringen Sie bitte den ersten Punkt.

Was ist Serialisierung?

Bei der Serialisierung wird der Status des Objekts dauerhaft festgelegt. Dies bedeutet, dass der Status des Objekts in einen Bytestrom konvertiert wird, der zum Fortbestehen (z. B. Speichern von Bytes in einer Datei) oder zum Übertragen (z. B. Senden von Bytes über ein Netzwerk) verwendet werden soll. Auf die gleiche Weise können wir die Deserialisierung verwenden, um den Status des Objekts aus Bytes wiederherzustellen. Dies ist eines der wichtigsten Konzepte in der Java-Programmierung, da die Serialisierung hauptsächlich in der Netzwerkprogrammierung verwendet wird. Die Objekte, die über das Netzwerk übertragen werden müssen, müssen in Bytes konvertiert werden. Zu diesem Zweck muss jede Klasse oder Schnittstelle die SerializableSchnittstelle implementieren . Es ist eine Markierungsschnittstelle ohne Methoden.

Was ist nun das transientSchlüsselwort und sein Zweck?

Standardmäßig werden alle Variablen des Objekts in einen dauerhaften Zustand konvertiert. In einigen Fällen möchten Sie möglicherweise vermeiden, dass einige Variablen beibehalten werden, da Sie diese Variablen nicht beibehalten müssen. Sie können diese Variablen also als deklarieren transient. Wenn die Variable als deklariert ist transient, wird sie nicht beibehalten. Das ist der Hauptzweck des transientSchlüsselworts.

Ich möchte die beiden oben genannten Punkte anhand des folgenden Beispiels erläutern:

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);
    }
}

Und die Ausgabe wird die folgende sein:

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

Der zweite Vorname wird als deklariert transient, sodass er nicht im dauerhaften Speicher gespeichert wird.

Quelle


26
Dieses Beispiel stammt aus diesem Code und kann hier gelesen werden: javabeat.net/2009/02/what-is-transient-keyword-in-java
Krishna

11
Dieser Teil erscheint mir seltsam und möglicherweise verwirrend: "Das heißt, der Status des Objekts wird in einen Bytestrom konvertiert und in einer Datei gespeichert. " Es scheint mir, dass die Serialisierung die meiste Zeit nicht das Schreiben in eine Datei beinhaltet (Beispiel: die folgenden Netzwerkbeispiele)
Garcia Hurtado

5
Das Beispiel ist schlecht, da der zweite Vorname eindeutig keine vorübergehende Eigenschaft ist.
Raphael

1
@ Raphael Für mich ist das Beispiel hilfreich und erklärt zumindest das Konzept. Würden Sie ein besseres Beispiel geben, wenn Sie sich dessen bewusst sind?
Chaklader Asfak Arefe

@ Yoda Wir könnten einen Verweis auf ein NameFormattergebrauchtes zum Fahren haben toString(). Oder irgendetwas anderes, das sich auf Konfiguration, Anzeige oder Geschäftslogik bezieht, im Gegensatz zu Daten.
Raphael

84

Damit können Sie Variablen definieren, die Sie nicht serialisieren möchten.

In einem Objekt befinden sich möglicherweise Informationen, die Sie nicht serialisieren / beibehalten möchten (möglicherweise ein Verweis auf ein übergeordnetes Factory-Objekt), oder die Serialisierung ist möglicherweise nicht sinnvoll. Wenn Sie diese als "vorübergehend" markieren, ignoriert der Serialisierungsmechanismus diese Felder.


36

Mein kleiner Beitrag:

Was ist ein Übergangsfeld?
Grundsätzlich ist jedes mit dem transientSchlüsselwort geänderte Feld ein Übergangsfeld.

Warum werden in Java Übergangsfelder benötigt?
Mit dem transientSchlüsselwort können Sie den Serialisierungsprozess steuern und einige Objekteigenschaften von diesem Prozess ausschließen. Der Serialisierungsprozess wird verwendet, um Java-Objekte beizubehalten, hauptsächlich, damit ihre Zustände beibehalten werden können, während sie übertragen oder inaktiv sind. Manchmal ist es sinnvoll, bestimmte Attribute eines Objekts nicht zu serialisieren.

Welche Felder sollten Sie als vorübergehend markieren?
Jetzt kennen wir den Zweck destransientBei Schlüsselwort- und Übergangsfeldern ist es wichtig zu wissen, welche Felder vorübergehend markiert werden sollen. Statische Felder werden ebenfalls nicht serialisiert, daher würde auch das entsprechende Schlüsselwort ausreichen. Aber dies könnte Ihr Klassendesign ruinieren. Hier kommt das transientSchlüsselwort zur Rettung. Ich versuche, die Serialisierung von Feldern, deren Werte von anderen abgeleitet werden können, nicht zuzulassen, daher markiere ich sie als vorübergehend. Wenn Sie ein Feld mit dem Namen haben, interestdessen Wert aus anderen Feldern ( principal, rate& time) berechnet werden kann , muss es nicht serialisiert werden.

Ein weiteres gutes Beispiel ist die Anzahl der Artikelwörter. Wenn Sie einen ganzen Artikel speichern, müssen Sie die Wortanzahl nicht speichern, da sie berechnet werden kann, wenn der Artikel "deserialisiert" wird. Oder denken Sie an Holzfäller;Logger Instanzen müssen fast nie serialisiert werden, damit sie vorübergehend gemacht werden können.


63
Ihr "einfacher Satz" ist lediglich eine Tautologie. Es erklärt nichts. Ohne wäre es besser für dich.
Marquis von Lorne

1
Dies ist eine gute Erklärung, wo das Feld sein solltetransient
Chaklader Asfak Arefe

1
Zinsfeld und Wortzahl sind gute Beispiele für Übergangsfelder.
Tarun

1
Ein weiterer guter Anwendungsfall: Wenn Ihr Objekt Komponenten wie Sockets enthält und Sie serialisieren möchten, was passiert dann mit dem Socket? Wenn würde bestehen bleiben, nach dem Deserialisieren, was würde die Steckdose halten? Es ist sinnvoll, dieses Socket-Objekt alstransient
Mohammed Siddiq

28

Eine transientVariable ist eine Variable, die möglicherweise nicht serialisiert wird.

Ein Beispiel dafür, wann dies nützlich sein könnte, sind Variablen, die nur im Kontext einer bestimmten Objektinstanz sinnvoll sind und die ungültig werden, sobald Sie das Objekt serialisiert und deserialisiert haben. In diesem Fall ist es hilfreich, diese Variablen nullstattdessen zu verwenden, damit Sie sie bei Bedarf mit nützlichen Daten neu initialisieren können.


Ja, so etwas wie "Passwort oder crediCardPin" -Feldmitglieder einer Klasse.
Mateen

17

transientwird verwendet, um anzuzeigen, dass ein Klassenfeld nicht serialisiert werden muss. Das wahrscheinlich beste Beispiel ist ein ThreadFeld. Es gibt normalerweise keinen Grund, a zu serialisieren Thread, da sein Status sehr "flussspezifisch" ist.


Korrigieren Sie mich, wenn ich falsch liege, aber der Thread nicht serialisierbar ist und trotzdem übersprungen wird?
TFennis

3
@TFennis: Wenn eine serialisierbare Klasse Aauf eine nicht serialisierbare Klasse verweist B(wie Threadin Ihrem Beispiel), Amuss entweder die Referenz markiert werden, da transientXOR den Standard-Serialisierungsprozess überschreiben muss, um mit BXOR etwas Vernünftiges zu tun, vorausgesetzt, dass nur serialisierbare Unterklassen von Btatsächlich referenziert werden (Die eigentliche Unterklasse muss sich also um ihre "schlechten" Eltern kümmern. B) XOR akzeptiert, dass die Serialisierung fehlschlägt. In nur einem Fall (als vorübergehend markiert) Bwird automatisch und stillschweigend übersprungen.
AH

3
@TFennis Nein, es wird eine Ausnahme verursachen.
Marquis von Lorne

1
@AH: Warum XOR? Ich würde denken, dass Code, der eine beliebige Kombination dieser Dinge ausführt, funktionieren würde, und einige Kombinationen könnten nützlich sein (z. B. kann das Überschreiben des Standard-Serialisierungsprozesses nützlich sein, selbst wenn nur auf serialisierbare Unterklassen von B verwiesen wird und umgekehrt).
Supercat

15

Andere Serialisierungssysteme als das native Java können ebenfalls diesen Modifikator verwenden. Im Ruhezustand bleiben beispielsweise keine Felder erhalten, die mit @Transient oder dem Transientenmodifikator markiert sind . Auch Terrakotta respektiert diesen Modifikator.

Ich glaube, die bildliche Bedeutung des Modifikators lautet: "Dieses Feld ist nur für den speicherinternen Gebrauch bestimmt. Behalten Sie es nicht bei oder verschieben Sie es in irgendeiner Weise außerhalb dieser bestimmten VM. Es ist nicht portierbar." Das heißt, Sie können sich nicht auf den Wert in einem anderen VM-Speicher verlassen. Ähnlich wie bei flüchtig bedeutet, dass Sie sich nicht auf bestimmte Speicher- und Thread-Semantiken verlassen können.


14
Ich denke, das transientwäre kein Schlüsselwort, wenn es zu diesem Zeitpunkt entworfen würde. Sie würden wahrscheinlich eine Anmerkung verwenden.
Joachim Sauer


7

Bevor ich auf diese Frage antworte, muss ich Ihnen die SERIALISIERUNG erklären , denn wenn Sie verstehen, was Serialisierung in Wissenschaftscomputern bedeutet, können Sie dieses Schlüsselwort leicht verstehen.

Serialisierung Wenn ein Objekt über das Netzwerk übertragen / auf einem physischen Medium (Datei, ...) gespeichert wird, muss das Objekt "serialisiert" werden. Die Serialisierung konvertiert Byte-Status-Objektreihen. Diese Bytes werden im Netzwerk gesendet / gespeichert und das Objekt wird aus diesen Bytes neu erstellt.
Beispiel

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

Wenn Sie nun das Feld NICHT ÜBERTRAGEN / GESPEICHERT dieses Objekts SO möchten , können Sie das Schlüsselwort verwenden transient

private transient attr2;

Beispiel


6

Dies ist erforderlich, wenn Sie keine vertraulichen Daten für die Serialisierung freigeben möchten.


7
Es gibt andere Anwendungsfälle als vertrauliche Daten, in denen Sie möglicherweise kein Feld serialisieren möchten. Zum Beispiel würden Sie wahrscheinlich niemals ein serialisieren wollen Thread(z. B. eine Gutschrift für @AH). In diesem Fall würden Sie es als vorübergehend markieren. Ein Thread ist jedoch an und für sich kein vertrauliches Datenelement. Es macht einfach keinen logischen Sinn, es zu serialisieren (und es ist nicht serialisierbar).
Glen3B

1
@ glen3b Dieser Fall wird durch diese Antwort nicht ausgeschlossen. Es ist sicherlich notwendig, wie die Dinge in dem Fall stehen, in dem das Poster erwähnt wird.
Marquis von Lorne

3

Laut Google Transient bedeutet == nur für kurze Zeit; unbeständig.

Wenn Sie nun in Java etwas vorübergehend machen möchten, verwenden Sie das Schlüsselwort transient.

F: Wo kann man Transient verwenden?

A: Im Allgemeinen können wir in Java Daten in Dateien speichern, indem wir sie in Variablen erfassen und diese Variablen in Dateien schreiben. Dieser Vorgang wird als Serialisierung bezeichnet. Wenn wir nun vermeiden möchten, dass Variablendaten in eine Datei geschrieben werden, würden wir diese Variable als vorübergehend festlegen.

transient int result=10;

Hinweis: Transiente Variablen können nicht lokal sein.


0

Einfach ausgedrückt, schützt das vorübergehende Java-Schlüsselwort Felder vor dem Serialisieren als nicht vorübergehende Felder.

In diesem Codefragment unserer abstrakten Klasse BaseJob implementieren Sie die serialisierbare Schnittstelle. Wir erweitern sie von BaseJob, müssen jedoch die entfernten und lokalen Datenquellen nicht serialisieren. Serialisieren Sie nur die Felder organisationName und 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;

   }
}

0

Vereinfachter Beispielcode für das Schlüsselwort transient.

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);
    }
}

0

Ein Feld, das mit einem Transientenmodifikator deklariert wird, nimmt nicht am serialisierten Prozess teil. Wenn ein Objekt serialisiert wird (in einem beliebigen Status gespeichert), werden die Werte seiner Übergangsfelder in der seriellen Darstellung ignoriert, während andere Felder als Übergangsfelder am Serialisierungsprozess teilnehmen. Dies ist der Hauptzweck des vorübergehenden Schlüsselworts.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.