Heim  >  Artikel  >  Java  >  Detaillierte Erklärung des transienten Schlüsselworts in Java

Detaillierte Erklärung des transienten Schlüsselworts in Java

angryTom
angryTomnach vorne
2019-11-26 16:14:581736Durchsuche

Um ehrlich zu sein, sind Freunde, die schon länger Java studieren, mit dem Schlüsselwort transient noch sehr unbekannt und haben es kaum verwendet, aber das Schlüsselwort transient spielt in Java eine unverzichtbare Rolle! Wenn ich darüber sprechen möchte, denke ich, dass es am wahrscheinlichsten ist, wenn es um Objektströme (auch serialisierte Streams genannt) in IO-Streams geht!

Detaillierte Erklärung des transienten Schlüsselworts in Java

Ich glaube, viele Leute werden sich nicht für dieses Schlüsselwort interessieren, bis sie darauf stoßen. Ich erinnere mich, dass Blogger zum ersten Mal beim Lesen des JDK-Quellcodes auf das Schlüsselwort stießen. Beim Erlernen von Java ist der Grund, warum das Schlüsselwort transient selten ist, tatsächlich untrennbar mit seiner Funktion verbunden: Die Hauptfunktion des Schlüsselworts transient besteht darin, zu verhindern, dass einige durch das Schlüsselwort transient geänderte Mitgliedsattributvariablen serialisiert werden. Genau aus diesem Grund werden Serialisierungsoperationen im Lernprozess selten verwendet, normalerweise in der tatsächlichen Entwicklung! Was die Serialisierung angeht, glaube ich, dass viele Anfänger verwirrt sind oder kein spezifisches Konzept haben etwas übertrieben, ein bisschen anmaßend, ich habe das Gefühl, geschlagen zu werden)

1 Was ist Serialisierung?

Apropos Serialisierung: Ein weiteres damit verbundenes Konzept ist die Deserialisierung. Keine Panik. Sich an die Serialisierung zu erinnern, ist gleichbedeutend mit der Erinnerung an die Deserialisierung, denn die Serialisierung ist das Gegenteil der Serialisierung Blogger empfiehlt, sich einfach an das Konzept der Serialisierung zu erinnern, um sich nicht zu verwirren.

(Empfohlenes Video: Java-Video-Tutorial)

Serialisierung professioneller Terminologiedefinitionen:

Java bietet einen Mechanismus zur Objektserialisierung. Ein Objekt kann durch eine Bytesequenz dargestellt werden, die Informationen wie die Daten des Objekts, den Typ des Objekts und die im Objekt gespeicherten Attribute enthält. Nachdem die Bytesequenz in die Datei geschrieben wurde, entspricht dies dem Beibehalten der Informationen eines Objekts in der Datei. Umgekehrt kann die Bytefolge aus der Datei zurückgelesen, das Objekt rekonstruiert und deserialisiert werden. Die Daten des Objekts, der Typ des Objekts und die im Objekt gespeicherten Dateninformationen können alle zum Erstellen von Objekten im Speicher verwendet werden.

Serialisierung: Byte——> Objekt

Eigentlich habe ich die obige Schlussfolgerung zusammengefasst. Wenn Sie sie nicht verstehen, beziehen Sie sich direkt auf die Definition der Fachbegriffe Denken Sie daran, nachdem Sie es verstanden haben. Wenn Sie sich nicht erinnern können, töten Sie mich bitte

Serialisierung des Diagramms:

Detaillierte Erklärung des transienten Schlüsselworts in Java

2. Warum Serialisierung?

Im vorherigen Abschnitt haben wir das Konzept der Serialisierung erwähnt. Nachdem wir das Konzept kennengelernt haben, müssen wir wissen, warum wir serialisieren müssen.

Bevor ich über die Gründe spreche, warum Serialisierung notwendig ist, möchte ich Ihnen als Blogger eine Kastanie geben:

Genau wie wenn Sie auf die Straße gehen, um Lebensmittel einzukaufen, besteht die allgemeine Vorgehensweise darin, Folgendes zu tun: Verpacken Sie sie in Plastiktüten, bis Sie nach Hause gehen. Wenn es Zeit zum Kochen ist, nehmen Sie das Geschirr heraus. Und diese Reihe von Operationen ist wie Serialisierung und Deserialisierung!

Serialisierung von Objekten in Java bezieht sich auf die Konvertierung von Objekten in Bytesequenzen. Diese Bytesequenzen enthalten die Daten und Informationen des Objekts. In Datenbanken oder Dateien kann es auch für Netzwerke verwendet werden Wenn wir den Cache verwenden (möglicherweise ist nicht genügend Speicherplatz auf der Festplatte vorhanden) oder RPC aus der Ferne aufrufen (Netzwerkübertragung), müssen wir unsere Entitätsklassen häufig dazu bringen, die serialisierbare Schnittstelle zu implementieren es serialisierbar.

Kastanien wurden während des Entwicklungsprozesses mit dem Schlüsselwort transient geändert:

Wenn ein Benutzer einige Passwörter und andere Informationen hat, möchte er diese aus Sicherheitsgründen nicht während des Netzwerkbetriebs übertragen. Diese Informationen entsprechen: Sie können der Variablen das Schlüsselwort transient hinzufügen. Mit anderen Worten: Der Lebenszyklus dieses Felds existiert nur im Speicher des Aufrufers und wird nicht zur Persistenz auf die Festplatte geschrieben.

Beispiele, die keine vorübergehende Schlüsselwortänderung während des Entwicklungsprozesses erfordern:

1. Feldwerte in einer Klasse können basierend auf anderen Feldern abgeleitet werden.

2. Welche Felder möchten je nach den spezifischen Geschäftsanforderungen nicht serialisiert werden?

Ich frage mich, ob Sie jemals darüber nachgedacht haben, warum sie nicht serialisiert werden sollten. Tatsächlich geht es vor allem darum, Speicherplatz zu sparen. Optimieren Sie das Programm!

PS: Ich erinnere mich, dass ich beim Betrachten des HashMap-Quellcodes festgestellt habe, dass ein Feld mit „transient“ geändert wurde. Es besteht wirklich keine Notwendigkeit, dieses modCount-Feld zu serialisieren, da es bedeutungslos ist ModCount wird hauptsächlich verwendet, um festzustellen, ob die HashMap geändert wurde (modCount erhöht sich automatisch während Put- und Remove-Vorgängen, es kann am Anfang ein beliebiger Wert sein, und 0 ist auch möglich (neu, deserialisiert). oder geklont). Es ist immer 0, wenn es herauskommt. Es besteht keine Notwendigkeit, seinen Wert beizubehalten.

Der ultimative Zweck nach der Serialisierung besteht natürlich darin, das ursprüngliche Java-Objekt zu deserialisieren und wiederherzustellen. Was würden Sie sonst nach der Serialisierung tun, um sie bequem in Plastiktüten zu verpacken? . Entfernen Sie die Plastiktüte, damit die serialisierte Bytesequenz in einem Java-Objekt wiederhergestellt werden kann.

3. Die Verwendung von Serialisierung und Transient

1. Die Klasse der zu serialisierenden Objekte muss die Serialisierungsschnittstelle implementieren: Java.lang.Serializable-Schnittstelle ( Eine Flag-Schnittstelle ohne abstrakte Methoden. Die meisten Klassen in Java implementieren diese Schnittstelle, z. B. String, Integer-Klasse usw. Klassen, die diese Schnittstelle nicht implementieren, serialisieren oder deserialisieren keinen Status und lösen eine NotSerializableException-Ausnahme aus.

2. Die unterste Ebene beurteilt, ob das aktuelle Objekt eine Instanz von Serializable ist. Die Serialisierung wird zur Beurteilung verwendet.

3. Verwenden Sie den Objektstrom ObjectOutputStream in Java, um die Serialisierung und die Deserialisierung des ObjectInputStream-Stroms abzuschließen

==ObjectOutputStream: Serialisierungsvorgang über die writeObject()-Methode== 

==ObjectInputStream: Deserialisierungsvorgang über die Methode readObject()==

4. Alle Eigenschaften dieser Klasse müssen serialisierbar sein. Wenn es ein Attribut gibt, das nicht serialisierbar sein muss, muss das Attribut als transient markiert und mit dem Schlüsselwort transient geändert werden.

Detaillierte Erklärung des transienten Schlüsselworts in Java

Aufgrund der Bytes muss es sich um Stream-Operationen handeln, das heißt, der Objektstream wird auch als Serialisierungsstream ObjectOutputstream bezeichnet. Lassen Sie uns die Serialisierung in verschiedenen Situationen analysieren . Aktionscode!

Hier empfehle ich den Lesern, die den Yichun-Blog lesen, wirklich dringend: Versuchen Sie bitte, ihn einzugeben. Denken Sie daran, ihn auf einen Blick mitzunehmen, oder kopieren Sie ihn und führen Sie ihn aus, insbesondere bei kleinen weißen Kinderschuhen. Vertrauen Sie mir ! Sie werden auf jeden Fall etwas anderes gewinnen. !

3.1. Die Serialisierbare Schnittstelle ist nicht für die Serialisierung implementiert

package TransientTest;
import java.io.*;

class UserInfo { //================================注意这里没有实现Serializable接口
    private String name;
    private transient String password;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.password = psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
            "name='" + name + '\'' +
            ", password='" + password + '\'' +
            '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) {

        UserInfo userInfo = new UserInfo("老王", "123");
        System.out.println("序列化之前信息:" + userInfo);

        try {
            ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt"));
            output.writeObject(new UserInfo("老王", "123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Laufende Ergebnisse

Detaillierte Erklärung des transienten Schlüsselworts in Java

Die Serialisierbare Schnittstelle ist serialisiert

Wenn wir die Implementierung der Serializable-Schnittstelle hinzufügen und ausführen, werden wir feststellen, dass der Inhalt der im Projekt angezeigten Datei userinfo.txt wie folgt aussieht:

Detaillierte Erklärung des transienten Schlüsselworts in Java

Tatsächlich ist das nicht der Punkt. Der Punkt ist, dass der Serialisierungsvorgang erfolgreich war!

3.3. Gewöhnliche Serialisierung

package TransientTest;
import java.io.*;

class UserInfo implements Serializable { //第一步实现Serializable接口
    private String name;
    private String password; //都是普通属性==============================

    public UserInfo(String name, String psw) {
        this.name = name;
        this.password = psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
            "name='" + name + '\'' +
            ", password='" + password + '\'' +
            '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        UserInfo userInfo = new UserInfo("程序员老王", "123");
        System.out.println("序列化之前信息:" + userInfo);

        try {
            ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步开始序列化操作
            output.writeObject(new UserInfo("程序员老王", "123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream input = new ObjectInputStream(new FileInputStream("userinfo.txt")); //第三步开始反序列化操作
            Object o = input.readObject(); //ObjectInputStream的readObject方法会抛出ClassNotFoundException
            System.out.println("序列化之后信息:" + o);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Laufendes Ergebnis:

序列化之前信息:UserInfo{name='程序员老王', password='123'}
序列化之后信息:UserInfo{name='程序员老王', password='123'}

3.4. Transiente Serialisierung

package TransientTest;
import java.io.*;

class UserInfo implements Serializable { //第一步实现Serializable接口
    private String name;
    private transient String password; //特别注意:属性由transient关键字修饰===========

    public UserInfo(String name, String psw) {
        this.name = name;
        this.password = psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
            "name='" + name + '\'' +
            ", password='" + password + '\'' +
            '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        UserInfo userInfo = new UserInfo("程序员老王", "123");
        System.out.println("序列化之前信息:" + userInfo);

        try {
            ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步开始序列化操作
            output.writeObject(new UserInfo("程序员老王", "123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream input = new ObjectInputStream(new FileInputStream("userinfo.txt")); //第三步开始反序列化操作
            Object o = input.readObject(); //ObjectInputStream的readObject方法会抛出ClassNotFoundException
            System.out.println("序列化之后信息:" + o);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Laufendes Ergebnis:

序列化之前信息:UserInfo{name='程序员老王', password='123'}
序列化之后信息:UserInfo{name='程序员老王', password='null'}

Sonderzahlung Beachten Sie das Ergebnis. Der mit der vorübergehenden Änderung hinzugefügte Attributwert ist der Standardwert null! Wenn das durch transient geänderte Attribut vom Typ int ist, muss sein Wert nach der Serialisierung 0 sein. Natürlich können Sie es versuchen. Dies bedeutet, dass als transient markierte Attribute nicht gespeichert werden, wenn das Objekt serialisiert wird (oder die Variable nicht beibehalten wird)

3.5, statische Serialisierungssituation

package TransientTest;
import java.io.*;

class UserInfo implements Serializable { //第一步实现Serializable接口
    private String name;
    private static String password; //特别注意:属性由static关键字修饰==============

    public UserInfo(String name, String psw) {
        this.name = name;
        this.password = psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
            "name='" + name + '\'' +
            ", password='" + password + '\'' +
            '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        UserInfo userInfo = new UserInfo("程序员老王", "123");
        System.out.println("序列化之前信息:" + userInfo);

        try {
            ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步开始序列化操作
            output.writeObject(new UserInfo("程序员老王", "123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream input = new ObjectInputStream(new FileInputStream("userinfo.txt")); //第三步开始反序列化操作
            Object o = input.readObject(); //ObjectInputStream的readObject方法会抛出ClassNotFoundException
            System.out.println("序列化之后信息:" + o);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Ausführungsergebnisse:

序列化之前信息:UserInfo{name='程序员老王', password='123'}
序列化之后信息:UserInfo{name='程序员老王', password='123'}

Zu diesem Zeitpunkt werden Sie fälschlicherweise denken, dass die statische Änderung auch serialisiert wurde. Tatsächlich ist dies nicht der Fall. Tatsächlich kann es hier leicht zu Verwirrung kommen. Offensichtlich kann das Herausnehmen von null (Standardwert) zeigen, dass es nicht zum Standardwert wird. Warum sagen Sie immer noch, dass statisch nicht serialisiert wird?

Tatsächlich ist der Wert des statischen Variablennamens in der Klasse nach der Deserialisierung tatsächlich der Wert der entsprechenden statischen Variablen in der aktuellen JVM. Dieser Wert befindet sich in der JVM und wird nicht aus der Deserialisierung abgeleitet. Mit anderen Worten, durch statische Variablen geänderte Variablen nehmen nicht an der Serialisierung teil! Aber wir können es nicht ohne Beweise sagen, ja, dann vergleichen wir die beiden Programme und wir werden es verstehen!

Das erste Programm: Dies ist ein Namensattributprogramm, das nicht durch Static geändert wurde:

package Thread;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserInfo implements Serializable {
    private String name;
    private transient String psw;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.psw = psw;
    }

    public String getName() {
        return name;
    }

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

    public String getPsw() {
        return psw;
    }

    public void setPsw(String psw) {
        this.psw = psw;
    }

    public String toString() {
        return "name=" + name + ", psw=" + psw;
    }
}
public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("程序员老过", "456");
        System.out.println(userInfo);
        try {
            // 序列化,被设置为transient的属性没有被序列化
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt"));
            o.writeObject(userInfo);
            o.close();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        try {
            //在反序列化之前改变name的值 =================================注意这里的代码
            userInfo.setName("程序员老改");
            // 重新读取内容
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt"));
            UserInfo readUserInfo = (UserInfo) in .readObject();
            //读取后psw的内容为null
            System.out.println(readUserInfo.toString());
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

Laufergebnisse:

name=程序员老过, psw=456name=程序员老过, psw=null

Laufergebnisse von Das Programm Wie aus der Abbildung ersichtlich ist, war der Versuch, den Wert von name vor der Deserialisierung zu ändern, erfolglos!

Das zweite Programm: Dies ist ein statisch geändertes Namensattributprogramm:

package Thread;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserInfo implements Serializable {
    private static final long serialVersionUID = 996890129747019948 L;
    private static String name;
    private transient String psw;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.psw = psw;
    }

    public String getName() {
        return name;
    }

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

    public String getPsw() {
        return psw;
    }

    public void setPsw(String psw) {
        this.psw = psw;
    }

    public String toString() {
        return "name=" + name + ", psw=" + psw;
    }
}
public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("程序员老过", "456");
        System.out.println(userInfo);
        try {
            // 序列化,被设置为transient的属性没有被序列化
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt"));
            o.writeObject(userInfo);
            o.close();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        try {
            //在反序列化之前改变name的值
            userInfo.setName("程序员老改");
            // 重新读取内容
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt"));
            UserInfo readUserInfo = (UserInfo) in .readObject();
            //读取后psw的内容为null
            System.out.println(readUserInfo.toString());
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

Laufergebnis:

name=程序员老过, psw=456name=程序员老改, psw=null

Aus dem Programmlaufergebnis Es kann Es ist ersichtlich, dass Programmierer versuchen, den Wert des Namens vor der Deserialisierung zu ändern, und das Ergebnis ist erfolgreich! Ist es jetzt ganz klar, wenn wir die beiden Programme vergleichen?

Die durch das Schlüsselwort „static“ geänderten Mitgliedsattribute werden besser in den Speicher geladen als nicht statische Mitgliedsattribute. Gleichzeitig ist es auch besser, durch statische Elemente in den Speicher eingegebene Mitgliedervariablen zu serialisieren, und alle Objekte sind es serialisiert. Eine statische Variable ist nicht Teil des Objektstatus und nimmt daher nicht an der Serialisierung teil. Daher ist es sinnlos, statische Variablen als transiente Variablen zu deklarieren. Daher ist der Wert des statischen Variablennamens in der Klasse nach der Deserialisierung tatsächlich der Wert der entsprechenden statischen Variablen in der aktuellen JVM. Dieser Wert befindet sich in der JVM und wird nicht aus der Deserialisierung abgeleitet.

3.6. Endgültige Serialisierungssituation

Für das letzte Schlüsselwort wird die endgültige Variable über den Wert direkt an der Serialisierung beteiligt sein Probieren Sie es aus. Überprüfen Sie die endgültige Änderung!

Das Wichtigste ist, dass „final“ und „transient“ gleichzeitig dieselbe Variable ändern können, und das Ergebnis ist das gleiche. Ich hoffe, Sie werden es hier erwähnen Seien Sie nicht verwirrt, wenn Sie in der Zukunft auf diese Situationen im Wasser stoßen!

Die Rolle von serialVersionUID in Java-Klassen

Da das Schlüsselwort „transient“ erwähnt wurde, muss Serialisierung erwähnt werden ? Wolltuch? Grundsätzlich ist diese serialVersionUID vorhanden, wenn eine Serialisierung vorliegt.

Detaillierte Erklärung des transienten Schlüsselworts in Java

serialVersionUID ist für den Serialisierungsmechanismus von Java geeignet. Einfach ausgedrückt überprüft der Serialisierungsmechanismus von Java die Versionskonsistenz, indem er die serialVersionUID der Klasse beurteilt. Beim Deserialisieren vergleicht die JVM die serialVersionUID im übergebenen Bytestream mit der serialVersionUID der entsprechenden lokalen Entitätsklasse. Wenn sie gleich sind, gelten sie als konsistent und können deserialisiert werden. Andernfalls wird eine inkonsistente Version angezeigt. nämlich InvalidCastException, kann manchmal während der Entwicklung geschrieben werden. Es wird empfohlen, es zu schreiben.

5. Zusammenfassung der transienten Schlüsselwörter

1. Wenn die Variable durch transient geändert wird, wird die Variable nicht serialisiert
Der transiente Nur das Schlüsselwort Variablen können geändert werden, Methoden und Klassen können jedoch nicht geändert werden.
3. Durch das Schlüsselwort static geänderte Variablen nehmen nicht an der Serialisierung teil. Eine statische Variable kann nicht serialisiert werden, unabhängig davon, ob sie durch transient geändert wird.
4. Der finale Variablenwert nimmt an der Serialisierung teil, und Final transient hat keinen Einfluss auf transient und nimmt auch nicht an der Serialisierung teil Hinweis: Lokale Variablen können nicht durch das Schlüsselwort transient geändert werden. Wenn es sich bei der Variablen um eine benutzerdefinierte Klassenvariable handelt, muss die Klasse die serialisierbare Schnittstelle implementieren

Der dritte zu beachtende Punkt ist: Der Wert der statischen Variablen in der Klasse nach der Deserialisierung ist tatsächlich die entsprechende statische Variable in die aktuelle JVM. Der Wert befindet sich in der JVM und wird nicht aus der Deserialisierung abgeleitet.

Fazit: Durch das Schlüsselwort transient geändert, wird es nicht serialisiert. Der Vorteil besteht darin, dass Speicherplatz gespart werden kann. Optimieren Sie das Programm! Was folgt ist, dass die durch transient geänderten Felder neu berechnet und initialisiert werden!

Dieser Artikel stammt von der chinesischen PHP-Website, Spalte

Java-Tutorial

, willkommen zum Lernen!

Das obige ist der detaillierte Inhalt vonDetaillierte Erklärung des transienten Schlüsselworts in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen