国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java ---- 序列化

zorpan / 3250人閱讀

摘要:使用對象序列化,在保存對象時,會把其狀態(tài)保存為一組字節(jié),在未來,再將這些字節(jié)組裝成對象。由此可知,對象序列化不會關(guān)注類中的靜態(tài)變量。對象的讀寫類中對象的序列化工作是通過和來完成的。這就是為什么在此序列化過程中的無參構(gòu)造器會被調(diào)用。

Java對象的序列化

Java平臺允許我們在內(nèi)存中創(chuàng)建可復(fù)用的Java對象,但一般情況下,只有當(dāng)JVM處于運行時,這些對象才可能存在,即,這些對象的生命周期不會比JVM的生命周期更長。但在現(xiàn)實應(yīng)用中,就可能要求在JVM停止運行之后能夠保存(持久化)指定的對象,并在將來重新讀取被保存的對象。Java對象序列化就能夠幫助我們實現(xiàn)該功能。

使用Java對象序列化,在保存對象時,會把其狀態(tài)保存為一組字節(jié),在未來,再將這些字節(jié)組裝成對象。必須注意地是,對象序列化保存的是對象的”狀態(tài)”,即它的成員變量。由此可知,對象序列化不會關(guān)注類中的靜態(tài)變量

簡而言之,就是讓對象想基本數(shù)據(jù)類型和字符串類型一樣,通過輸入輸出字節(jié)流ObjectInputStream 和 ObjectOutputStream進行寫和讀操作。

Java序列化的應(yīng)用場景

當(dāng)你想把的內(nèi)存中的對象狀態(tài)保存到一個文件中或者數(shù)據(jù)庫中時候

當(dāng)你想用套接字在網(wǎng)絡(luò)上傳送對象的時候

當(dāng)你想通過RMI傳輸對象的時候

如何對Java對象進行序列化與反序列化

在Java中,只要一個類實現(xiàn)了java.io.Serializable接口,那么它就可以被序列化。

import java.io.*;
import java.util.*;

class User implements Serializable {
    private String name;
    private int age;
    private Date birthday;
    private transient String gender;
    private static int test =1;
    private static final long serialVersionUID = -6849794470754667710L;

    public User() {
        System.out.println("none-arg constructor");
    }

    public User(String name, Integer age,Date birthday,String gender) {
        System.out.println("arg constructor");
        this.name = name;
        this.age = age;
        this.birthday = birthday;
        this.gender = gender;
    }

    public void setTest(int Newtest) {
        this.test = Newtest;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "User{" +
                "name="" + name + """ +
                ", age=" + age +
                ", gender=" + gender +
                ", birthday=" + birthday +
                ", testStatic="+test+
                "}"+" "+super.toString();
    }
}

public class SerializableDemo {
    public static void main(String[] args) throws Exception {
        //Initializes The Object
        User user = new User("qiuyu",23,new Date(),"male");
        System.out.println(user);
        user.setTest(10);
        System.out.println(user);

        //Write Obj to File
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tempFile"));
        out.writeObject(user);
        out.close();

        //Read Obj from File
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("tempFile"));
        User newUser = (User) in.readObject();
        System.out.println(newUser);
        in.close();
    }
}

此時的輸出為:

arg constructor
User{name="qiuyu", age=23, gender=male, birthday=Tue Nov 14 20:38:57 GMT+08:00 2017, testStatic=10} User@326de728
User{name="qiuyu", age=23, gender=null, birthday=Tue Nov 14 20:38:57 GMT+08:00 2017, testStatic=10} User@4883b407

此時必須注意的是,當(dāng)重新讀取被保存的User對象時,并沒有調(diào)用User的任何構(gòu)造器,看起來就像是直接使用字節(jié)將User對象還原出來的。

當(dāng)User對象被保存到tempfile文件中之后,我們可以在其它地方去讀取該文件以還原對象,但必須確保該讀取程序的CLASSPATH中包含有User.class,否則會拋出ClassNotFoundException。

Q:之前不是說序列化不保存靜態(tài)變量么,為什么這里的靜態(tài)變量進行了傳遞,都變成了10呢?
A:因為此時User.class已經(jīng)被加載進了內(nèi)存中,且將static變量test從1更改為了10。當(dāng)我們恢復(fù)對象時,會直接獲取當(dāng)前static的變量test的值,所以為10。

Q:但如果我們的恢復(fù)操作在另一個文件中進行,結(jié)果會怎么樣呢?

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class Recovering {
    public static void main(String[] args) throws Exception{
        //Read Obj from File
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("tempFile"));
        User newUser = (User) in.readObject();
        System.out.println(newUser);
        in.close();
    }
}

輸出結(jié)果為:

User{name="qiuyu", age=23, gender=null, birthday=Tue Nov 14 20:38:57 GMT+08:00 2017, testStatic=1} User@6442b0a6

A:因為在運行此代碼時,User.class會被加載進內(nèi)存,然后執(zhí)行初始化,將被初始化為1,因此test變量會被恢復(fù)為1。注意區(qū)分上面兩種情況,不要因為是在本地進行測試,就認(rèn)為static會被序列化,同時要了解Java運行時,內(nèi)存加載的機制。

基本知識點

Serializable接口

對于任何需要被序列化的對象,都必須要實現(xiàn)接口Serializable,它只是一個標(biāo)識接口本身沒有任何成員,只是用來標(biāo)識說明當(dāng)前的實現(xiàn)類的對象可以被序列化.

如果父類實現(xiàn)序列化,子類自動實現(xiàn)序列化,不需要顯式實現(xiàn)Serializable接口。

如果被寫對象的類型是String數(shù)組EnumSerializable,那么就可以對該對象進行序列化,否則將拋出NotSerializableException。

對象的讀寫

Java類中對象的序列化工作是通過 ObjectOutputStream ObjectInputStream 來完成的。

使用readObject()writeObject()方法對對象進行讀寫操作;

對于基本類型,可以使用readInt()writeInt() , readDouble()writeDouble()等類似的接口進行讀寫。

序列化機制

如果僅僅只是讓某個類實現(xiàn)Serializable接口,而沒有其它任何處理的話,則就是使用默認(rèn)序列化機制。使用默認(rèn)機制,在序列化對象時,不僅會序列化當(dāng)前對象本身,還會對該對象引用的其它對象也進行序列化,同樣地,這些其它對象引用的另外對象也將被序列化。

在現(xiàn)實應(yīng)用中,有些時候不能使用默認(rèn)序列化機制。比如,希望在序列化過程中忽略掉敏感數(shù)據(jù),或者簡化序列化過程。為此需要為某個字段聲明為transient,那么序列化機制就會忽略被transient修飾的字段。transient的引用變量會以null返回,基本數(shù)據(jù)類型會以相應(yīng)的默認(rèn)值返回。(例如:引用類型沒有實現(xiàn)Serializable,或者動態(tài)數(shù)據(jù)只可以在執(zhí)行時求出而不能或不必存儲)

writeObject()與readObject()

對于上被聲明為transient的字段gender,除了將transient關(guān)鍵字去掉之外,是否還有其它方法能使它再次可被序列化?方法之一就是在User類中添加兩個方法:writeObject()與readObject(),如下所示:

private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeUTF(gender);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        gender = in.readUTF();
    }

在writeObject()方法中會先調(diào)用ObjectOutputStream中的defaultWriteObject()方法,該方法會執(zhí)行默認(rèn)的序列化機制,此時會忽略掉gender字段。

然后再調(diào)用writeUtf()方法顯示地將gender字段寫入到ObjectOutputStream中。readObject()的作用則是針對對象的讀取,其原理與writeObject()方法相同。

Q: writeObject()與readObject()都是private方法,那么它們是如何被調(diào)用的呢?
A: 毫無疑問,是使用反射。(注意這不是繼承接口的方法,因為接口類的方法都是public的,而這里的方法是private的)

Externalizable接口

無論是使用transient關(guān)鍵字,還是使用writeObject()和readObject()方法,其實都是基于Serializable接口的序列化。JDK中提供了另一個序列化接口Externalizable,使用該接口之后,之前基于Serializable接口的序列化機制就將失效。

import java.io.*;
import java.util.*;

class UserExtern implements Externalizable {
    private String name;
    private int age;
    private Date birthday;
    private transient String gender;
    private static int test =1;
    private static final long serialVersionUID = -6849794470754667710L;

    public UserExtern() {
        System.out.println("none-arg constructor");
    }

    public UserExtern(String name, Integer age,Date birthday,String gender) {
        System.out.println("arg constructor");
        this.name = name;
        this.age = age;
        this.birthday = birthday;
        this.gender = gender;
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeUTF(gender);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        gender = in.readUTF();
    }


    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(name);
        out.writeInt(age);
        out.writeObject(birthday);
        out.writeUTF(gender);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = in.readUTF();
        age = in.readInt();
        birthday = (Date) in.readObject();
        gender = in.readUTF();
    }


    public void setTest(int Newtest) {
        this.test = Newtest;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "User{" +
                "name="" + name + """ +
                ", age=" + age +
                ", gender=" + gender +
                ", birthday=" + birthday +
                ", testStatic="+test+
                "}"+" "+super.toString();
    }
}



public class ExternalizableDemo {
    public static void main(String[] args) throws Exception {
        UserExtern userExtern = new UserExtern("qiuyu",23,new Date(),"male");
        System.out.println(userExtern);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("external"));
        out.writeObject(userExtern);
        out.close();


        ObjectInputStream in = new ObjectInputStream(new FileInputStream("external"));
        UserExtern userExtern1 = (UserExtern)in.readObject();
        System.out.println(userExtern1)
    }
}

輸出結(jié)果為:

arg constructor
User{name="qiuyu", age=23, gender=male, birthday=Tue Nov 14 22:34:25 GMT+08:00 2017, testStatic=1} UserExtern@25618e91
none-arg constructor
User{name="qiuyu", age=23, gender=male, birthday=Tue Nov 14 22:34:25 GMT+08:00 2017, testStatic=1} UserExtern@604ed9f0

Externalizable繼承于Serializable,當(dāng)使用該接口時,序列化的細(xì)節(jié)需要由程序員去完成writeExternal()readExternal()方法的具體細(xì)節(jié),以及哪些狀態(tài)需要進行序列化。

另外,若使用Externalizable進行序列化,當(dāng)讀取對象時,會調(diào)用被序列化類的無參構(gòu)造器去創(chuàng)建一個新的對象,然后再將被保存對象的字段的值分別填充到新對象中。這就是為什么在此序列化過程中UserExtern的無參構(gòu)造器會被調(diào)用。由于這個原因,實現(xiàn)Externalizable接口的類必須要提供一個無參的構(gòu)造器,且它的訪問權(quán)限為public

注意事項

讀取對象的順序必須與寫入的順序相同

如果有不能被序列化的對象,執(zhí)行期間就會拋出NotSerializableException異常

序列化時,只對對象的狀態(tài)進行保存,而不管對象的方法

靜態(tài)變量不會被序列化,因為所有的對象共享同一份靜態(tài)變量的值

如果一個對象的成員變量是一個對象,那么這個對象的數(shù)據(jù)成員也會被保存還原,而且會是遞歸的方式(對象網(wǎng))。(序列化程序會將對象版圖上的所有東西儲存下來,這樣才能讓該對象恢復(fù)到原來的狀態(tài))

如果子類實現(xiàn)Serializable接口而父類未實現(xiàn)時,父類不會被序列化,但此時父類必須有個無參構(gòu)造方法,否則會拋InvalidClassException異常;因為反序列化時會恢復(fù)原有子對象的狀態(tài),而父類的成員變量也是原有子對象的一部分。由于父類沒有實現(xiàn)序列化接口,即使沒有顯示調(diào)用,也會默認(rèn)執(zhí)行父類的無參構(gòu)造函數(shù)使變量初始化;

深入理解

序列化ID的問題

serialVersionUID適用于JAVA的序列化機制。簡單來說,Java的序列化機制是通過判斷類的serialVersionUID來驗證版本一致性的。

在進行反序列化時,JVM會把傳來的字節(jié)流中的serialVersionUID與本地相應(yīng)實體類的serialVersionUID進行比較,如果相同就認(rèn)為是一致的,可以進行反序列化,否則就會出現(xiàn)序列化版本不一致的異常,即是InvalidCastException。

序列化存儲規(guī)則

Java 序列化機制為了節(jié)省磁盤空間,具有特定的存儲規(guī)則,當(dāng)寫入文件的為同一對象時,并不會再將對象的內(nèi)容進行存儲,而只是再次存儲一份引用;

序列化到同一個文件時,如第二次修改了相同對象屬性值再次保存時候,虛擬機根據(jù)引用關(guān)系知道已經(jīng)有一個相同對象已經(jīng)寫入文件,因此只保存第二次寫的引用,所以讀取時,都是第一次保存的對象,第二次進行的修改將無效。

    public static void main(String[] args) throws Exception {
        //Initializes The Object
        User user = new User("qiuyu",23,new Date(),"male");
        user.setTest(10);
        System.out.println(user);


        //Write Obj to File
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tempFile"));
        out.writeObject(user);
        user.setAge(25);
        System.out.println(user);
        out.writeObject(user);
        out.close();

        //Read Obj from File
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("tempFile"));
        User newUser = (User) in.readObject();
        User newUser1 = (User) in.readObject();
        System.out.println(newUser);
        System.out.println(newUser1);
        in.close();
    }

輸出結(jié)果: 注意觀察age的值

User{name="qiuyu", age=23, gender=male, birthday=Tue Nov 14 22:47:22 GMT+08:00 2017, testStatic=10} User@326de728
User{name="qiuyu", age=25, gender=male, birthday=Tue Nov 14 22:47:22 GMT+08:00 2017, testStatic=10} User@326de728
User{name="qiuyu", age=23, gender=male, birthday=Tue Nov 14 22:47:22 GMT+08:00 2017, testStatic=10} User@4883b407
User{name="qiuyu", age=23, gender=male, birthday=Tue Nov 14 22:47:22 GMT+08:00 2017, testStatic=10} User@4883b407

多次序列化的問題

在一次的序列化的過程中,ObjectOutputStream 會在文件開始的地方寫入一個 Header的信息到文件中。于是在多次序列化的過程中就會繼續(xù)在文件末尾(本次序列化的開頭)寫入 Header 的信息,這時如果進行反序列化的對象的時候會報錯:java.io.StreamCorruptedException: invalid type code: AC

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/68007.html

相關(guān)文章

  • 小伙子,你真的搞懂 transient 關(guān)鍵字了嗎?

    摘要:由以上結(jié)果分析可知,靜態(tài)變量不能被序列化,示例讀取出來的是在內(nèi)存中存儲的值。關(guān)鍵字總結(jié)修飾的變量不能被序列化只作用于實現(xiàn)接口只能用來修飾普通成員變量字段不管有沒有修飾,靜態(tài)變量都不能被序列化好了,棧長花了半天時間,終于整理完了。 先解釋下什么是序列化 我們的對象并不只是存在內(nèi)存中,還需要傳輸網(wǎng)絡(luò),或者保存起來下次再加載出來用,所以需要Java序列化技術(shù)。 Java序列化技術(shù)正是將對象轉(zhuǎn)...

    curlyCheng 評論0 收藏0
  • Java 對象列化

    摘要:對象序列化對象序列化機制允許把內(nèi)存中的對象轉(zhuǎn)換成與平臺無關(guān)的二進制流,從而可以保存到磁盤或者進行網(wǎng)絡(luò)傳輸,其它程序獲得這個二進制流后可以將其恢復(fù)成原來的對象。 對象序列化 對象序列化機制允許把內(nèi)存中的Java對象轉(zhuǎn)換成與平臺無關(guān)的二進制流,從而可以保存到磁盤或者進行網(wǎng)絡(luò)傳輸,其它程序獲得這個二進制流后可以將其恢復(fù)成原來的Java對象。 序列化機制可以使對象可以脫離程序的運行而對立存在 ...

    tianyu 評論0 收藏0
  • Java開發(fā)中對象的列化與反列化

    摘要:在中,對象的序列化與反序列化被廣泛應(yīng)用到遠程方法調(diào)用及網(wǎng)絡(luò)傳輸中。相關(guān)接口及類為了方便開發(fā)人員將對象進行序列化及反序列化提供了一套方便的來支持。未實現(xiàn)此接口的類將無法使其任何狀態(tài)序列化或反序列化。 序列化與反序列化 序列化 (Serialization)是將對象的狀態(tài)信息轉(zhuǎn)換為可以存儲或傳輸?shù)男问降倪^程。一般將一個對象存儲至一個儲存媒介,例如檔案或是記億體緩沖等。在網(wǎng)絡(luò)傳輸過程中,可以...

    fox_soyoung 評論0 收藏0
  • Java列化

    摘要:的序列化是將一個對象表示成字節(jié)序列,該字節(jié)序列包括了對象的數(shù)據(jù),有關(guān)對象的類型信息和存儲在對象中的數(shù)據(jù)類型。任何實現(xiàn)了接口的類都可以被序列化。一旦對象被序列化或者重新裝配,就會分別調(diào)用那兩個方法。 Java序列化 1. 什么是序列化? 序列化是將一個對象的狀態(tài),各屬性的值序列化保存起來,然后在合適的時候通過反序列化獲得。 Java的序列化是將一個對象表示成字節(jié)序列,該字節(jié)序列包括了對象...

    lbool 評論0 收藏0
  • 淺談Java列化

    摘要:的序列化是將一個對象表示成字節(jié)序列,該字節(jié)序列包括了對象的數(shù)據(jù),有關(guān)對象的類型信息和存儲在對象中的數(shù)據(jù)類型。這個是根據(jù)類名接口名成員方法及屬性等來生成一個位的哈希字段,因為增加了字段,因此生成的不一樣了。 Java序列化 什么是序列化? 序列化是將一個對象的狀態(tài),各屬性的值序列化保存起來,然后在合適的時候通過反序列化獲得。 Java的序列化是將一個對象表示成字節(jié)序列,該字節(jié)序列包括了對...

    winterdawn 評論0 收藏0
  • java列化和反列化說起

    摘要:從的序列化和反序列化說起序列化是將對象的狀態(tài)信息轉(zhuǎn)換為可以存儲或傳輸?shù)男问降倪^程,而相反的過程就稱為反序列化。當(dāng)使用接口來進行序列化與反序列化的時候需要開發(fā)人員重寫與方法。 從java的序列化和反序列化說起 序列化 (Serialization)是將對象的狀態(tài)信息轉(zhuǎn)換為可以存儲或傳輸?shù)男问降倪^程,而相反的過程就稱為反序列化。 在java中允許我們創(chuàng)建可復(fù)用的對象,但是這些對象僅僅存在j...

    whlong 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<