Heim  >  Artikel  >  Java  >  Sprechen Sie über Serialisierung und Deserialisierung in Java-Objekten

Sprechen Sie über Serialisierung und Deserialisierung in Java-Objekten

青灯夜游
青灯夜游nach vorne
2020-07-03 10:03:592388Durchsuche

Sprechen Sie über Serialisierung und Deserialisierung in Java-Objekten

1. Das Konzept der Serialisierung und Deserialisierung

Konvertieren Sie das Objekt in den Prozess der Bytefolge wird Serialisierung von Objekten genannt .

Der Vorgang des Wiederherstellens einer Bytesequenz in einem Objekt wird als Deserialisierung des Objekts bezeichnet .

Die Serialisierung von Objekten hat zwei Hauptzwecke:

1) Speichern Sie die Bytesequenz des Objekts dauerhaft auf der Festplatte, normalerweise in einer Datei

2) Übertragen Sie die Bytesequenz des Objekts über das Netzwerk.

In vielen Anwendungen ist es notwendig, bestimmte Objekte zu serialisieren, damit sie den Speicherplatz verlassen und zur Langzeitspeicherung auf der physischen Festplatte gespeichert werden können. Das häufigste ist beispielsweise das Sitzungsobjekt auf dem Webserver. Wenn 100.000 Benutzer gleichzeitig darauf zugreifen, sind möglicherweise 100.000 Sitzungsobjekte vorhanden, was möglicherweise zu viel für den Speicher ist, sodass der Webcontainer einige Sitzungen auf der Festplatte serialisiert Zuerst die Festplatte usw. Wenn Sie es verwenden möchten, stellen Sie das auf der Festplatte gespeicherte Objekt im Speicher wieder her.

Wenn zwei Prozesse remote kommunizieren, können sie einander verschiedene Arten von Daten senden. Unabhängig von der Art der Daten werden sie in Form einer Binärsequenz über das Netzwerk übertragen. Der Sender muss dieses Java-Objekt in eine Bytesequenz umwandeln, bevor es über das Netzwerk übertragen werden kann. Der Empfänger muss die Bytesequenz in ein Java-Objekt wiederherstellen.

2. Serialisierungs-API in der JDK-Klassenbibliothek

java.io.ObjectOutputStream repräsentiert den Objektausgabestream und sein writeObject(Object obj ) Die Methode kann das durch den Parameter angegebene obj-Objekt serialisieren und die resultierende Bytesequenz in einen Zielausgabestream schreiben.
java.io.ObjectInputStream stellt einen Objekteingabestream dar. Seine Methode readObject() liest eine Folge von Bytes aus einem Quelleingabestream, deserialisiert sie in ein Objekt und gibt es zurück.
Nur Objekte von Klassen, die die Schnittstellen Serializable und Externalizable implementieren, können serialisiert werden. Die externalisierbare Schnittstelle erbt von Serialisierbare Schnittstelle: Klassen, die die Externalisierbare Schnittstelle implementieren, steuern das Serialisierungsverhalten vollständig selbst, während Klassen, die nur die Serialisierbare Schnittstelle implementieren, dies können Verwenden Sie die Standard-Serialisierungsmethode.
 Die Objektserialisierung umfasst die folgenden Schritte:
 1) Erstellen Sie einen Objektausgabestream, der einen Zielausgabestream anderer Typen umschließen kann, z. B. einen Dateiausgabestream.
 2) Über writeObject() des Objektausgabestream-Methode schreibt Objekt.

Die Schritte zur Objektdeserialisierung sind wie folgt:
1) Erstellen Sie einen Objekteingabestream, der einen anderen Typ von Quelleingabestream umschließen kann, z. B. einen Dateieingabestream.
2) Übergeben Der Objekteingabestrom Die Methode readObject() liest das Objekt.

Beispiele für die Serialisierung und Deserialisierung von Objekten:

Definieren Sie eine Person-Klasse und implementieren Sie die Serializable-Schnittstelle

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

  Serialisieren und Deserialisieren von Person-Klassenobjekten

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

}

Die Ergebnisse der Codeausführung lauten wie folgt:

Sprechen Sie über Serialisierung und Deserialisierung in Java-Objekten

Nach erfolgreicher Serialisierung von Person A Person .txt-Datei wird auf dem E-Laufwerk generiert, und die deserialisierte Person generiert ein Person-Objekt, nachdem sie die Person.txt des E-Laufwerks gelesen hat

3. Die Rolle von serialVersionUID

serialVersionUID: bedeutet wörtlich die serialisierte Versionsnummer. Jede Klasse, die die Serializable-Schnittstelle implementiert, verfügt über eine statische Variable, die die serialisierte Versionskennung darstellt

private static final long serialVersionUID

Wenn serialVersionUID nicht zur Klasse hinzugefügt wird, die die Serializable-Schnittstelle implementiert, wird die folgende Warnmeldung angezeigt

Sprechen Sie über Serialisierung und Deserialisierung in Java-Objekten

Klicken Sie mit der Maus auf ein Dialogfeld zum Generieren von serialVersionUID wird angezeigt, wie unten gezeigt:

Sprechen Sie über Serialisierung und Deserialisierung in Java-Objekten

Es gibt zwei Möglichkeiten, serialVersionUID zu generieren:

Verwenden Sie this Die dadurch generierte serialVersionUID Methode ist 1L, zum Beispiel:

private static final long serialVersionUID = 1L;

Die von generierte serialVersionUID basiert auf dem Klassennamen, dem Schnittstellennamen, der Methode und dem Attribut usw., zum Beispiel:

private static final long serialVersionUID = 4603642343377807741L;

Nach dem Hinzufügen Die Warnung wird nicht angezeigt, wie unten gezeigt:

Sprechen Sie über Serialisierung und Deserialisierung in Java-Objekten

Was ist nach so viel die serialVersionUID (serialisierte Versionsnummer)? Das folgende Beispiel soll die Rolle von serialVersionUID veranschaulichen. Sehen Sie sich den folgenden Code an:

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>

Laufendes Ergebnis:

Sprechen Sie über Serialisierung und Deserialisierung in Java-ObjektenSprechen Sie über Serialisierung und Deserialisierung in Java-Objekten

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

下面我们修改一下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;
    }
}

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

Sprechen Sie über Serialisierung und Deserialisierung in Java-Objekten

四、serialVersionUID的取值

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

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

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

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

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

推荐学习:Java视频教程

Das obige ist der detaillierte Inhalt vonSprechen Sie über Serialisierung und Deserialisierung in Java-Objekten. 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