成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java序列化

lbool / 1777人閱讀

摘要:的序列化是將一個(gè)對(duì)象表示成字節(jié)序列,該字節(jié)序列包括了對(duì)象的數(shù)據(jù),有關(guān)對(duì)象的類型信息和存儲(chǔ)在對(duì)象中的數(shù)據(jù)類型。任何實(shí)現(xiàn)了接口的類都可以被序列化。一旦對(duì)象被序列化或者重新裝配,就會(huì)分別調(diào)用那兩個(gè)方法。

Java序列化 1. 什么是序列化?

序列化是將一個(gè)對(duì)象的狀態(tài),各屬性的值序列化保存起來,然后在合適的時(shí)候通過反序列化獲得。

Java的序列化是將一個(gè)對(duì)象表示成字節(jié)序列,該字節(jié)序列包括了對(duì)象的數(shù)據(jù),有關(guān)對(duì)象的類型信息和存儲(chǔ)在對(duì)象中的數(shù)據(jù)類型。

說白了,就是將對(duì)象保存起來,就跟保存字符串?dāng)?shù)據(jù)一樣,用到的時(shí)候再取出來。任何實(shí)現(xiàn)了Serializable接口的類都可以被序列化。

2. 實(shí)現(xiàn)Serializable接口進(jìn)行序列化
package com.wangjun.othersOfJava;

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

public class SerializeDemo {

    public static void main(String[] args) {
        Employee em = new Employee();
        em.name = "wangjun";
        em.age = 24;
        em.ssh = 123456;
        // 將對(duì)象序列化后保存到文件
        try (
                FileOutputStream fo = new FileOutputStream("tem.ser");
                ObjectOutputStream oo = new ObjectOutputStream(fo))
        {
            oo.writeObject(em);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 反序列化取出對(duì)象
        try(
                FileInputStream fi = new FileInputStream("tem.ser");
                ObjectInputStream oi = new ObjectInputStream(fi)) 
        {
            Employee e2 = (Employee) oi.readObject();
            System.out.println(e2.name);
            System.out.println(e2.age);
            System.out.println(e2.ssh);
            System.out.println(Employee.local);
            e2.test();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class Employee implements Serializable {
        String name;
        int age;
        static String local = "earth";
        transient int ssh;

        public void test() {
            System.out.println("this is test method!");
        }
    }

}

程序的運(yùn)行結(jié)果:

wangjun
24
0
earth
this is test method!

如果有一些字段不想被序列化怎么辦呢?這時(shí)候就可以用transient關(guān)鍵字修飾,就像上面代碼的ssh字段,關(guān)于transient關(guān)鍵字有以下幾個(gè)特點(diǎn):

一旦被transient關(guān)鍵字修飾,那變量將不再是對(duì)象持久化的一部分,該變量?jī)?nèi)容在序列化后無法獲得訪問;

transient只能修飾變量,不能修飾方法和類,本地變量(局部變量)也不能被transient修飾;

一個(gè)靜態(tài)變量不管是否被transient修飾,都不能被序列化。

從上面的例子看到好像與第三條不符,其實(shí)反序列化取出的local是JVM里面的值,而不是反序列化出來的??梢约右恍写a驗(yàn)證一下,在反序列化之前更改一下local的值:

// 反序列化取出對(duì)象
Employee.local = "earth2";
try(
  ...

看一下打印結(jié)果

wangjun
24
0
earth2
this is test method!

這說明打印出來的是JVM中對(duì)應(yīng)的local的值earth2,而不是序列化的時(shí)候的值earth。

3. 實(shí)現(xiàn)Externalizable接口進(jìn)行序列化

transient只有對(duì)實(shí)現(xiàn)了Serializable接口方式的序列化有效,還有一種序列化的方式是實(shí)現(xiàn)Externalizable接口,這種實(shí)現(xiàn)方式不像實(shí)現(xiàn)Serializable接口一樣可以幫你自動(dòng)序列化,它需要在writeExternal方法中手動(dòng)指定需要序列化的變量并且在readExternal手動(dòng)取出來,這與是否被transient修飾無關(guān),下面更改一下上面的例子,將Employee類改成:

static class Employee implements Externalizable {
        String name;
        int age;
        static String local = "earth";
        transient int ssh;
        
        //實(shí)現(xiàn)Externalizable接口進(jìn)行序列化必須顯式聲明無參構(gòu)造器
        public Employee() {
        }

        public void test() {
            System.out.println("this is test method!");
        }

        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeObject(name);
            //out.writeObject(age);
            out.writeObject(ssh);
            out.writeObject(local);
        }

        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            name = (String) in.readObject();
            //age = (int) in.readObject();
            ssh = (int) in.readObject();
            local = (String) in.readObject();
        }
    }

重新運(yùn)行,結(jié)果(注意:上述主函數(shù)中還存在對(duì)local重新賦值的代碼Employee.local = "earth2";):

wangjun
0
123456
earth
this is test method!

可以看到能否被序列化跟transient和static修飾都沒有關(guān)系,只跟writeExternal和readExternal有關(guān)系。

4. Serializable和Externalizable的區(qū)別

對(duì)Serializable對(duì)象反序列化時(shí),由于Serializable對(duì)象完全以它存儲(chǔ)的二進(jìn)制位為基礎(chǔ)來構(gòu)造,因此并不會(huì)調(diào)用任何構(gòu)造函數(shù),因此Serializable類無需默認(rèn)構(gòu)造函數(shù),但是當(dāng)Serializable類的父類沒有實(shí)現(xiàn)Serializable接口時(shí),反序列化過程會(huì)調(diào)用父類的默認(rèn)構(gòu)造函數(shù),因此該父類必需有默認(rèn)構(gòu)造函數(shù),否則會(huì)拋異常。

對(duì)Externalizable對(duì)象反序列化時(shí),會(huì)先調(diào)用類的不帶參數(shù)的構(gòu)造方法,這是有別于默認(rèn)反序列方式的。如果把類的不帶參數(shù)的構(gòu)造方法刪除,或者把該構(gòu)造方法的訪問權(quán)限設(shè)置為private、默認(rèn)或protected級(jí)別,會(huì)拋出java.io.InvalidException: no valid constructor異常,因此Externalizable對(duì)象必須有默認(rèn)構(gòu)造函數(shù),而且必需是public的。

如果不是特別堅(jiān)持實(shí)現(xiàn)Externalizable接口,那么還有另一種方法。我們可以實(shí)現(xiàn)Serializable接口,并添加writeObject()readObject()的方法。一旦對(duì)象被序列化或者重新裝配,就會(huì)分別調(diào)用那兩個(gè)方法。也就是說,只要提供了這兩個(gè)方法,就會(huì)優(yōu)先使用它們,而不考慮默認(rèn)的序列化機(jī)制。

5. SerialVersionUID的作用

上述實(shí)現(xiàn)Serializable接口的Employee類中,會(huì)有一個(gè)警告:

The serializable class Employee does not declare a static final serialVersionUID field of type long

意思是Employee沒有聲明一個(gè)靜態(tài)final的常量serialVersionUID,那這個(gè)serialVersionUID的作用是什么呢?

serialVersionUID是對(duì)類進(jìn)行版本控制的,Java的序列化機(jī)制是通過判斷類的serialVersionUID來驗(yàn)證版本一致性的。在進(jìn)行反序列化時(shí),JVM會(huì)把傳來的字節(jié)流中的serialVersionUID與本地相應(yīng)實(shí)體類的serialVersionUID進(jìn)行比較,如果相同就認(rèn)為是一致的,可以進(jìn)行反序列化,否則就會(huì)出現(xiàn)序列化版本不一致的異常,即是InvalidCastException。

serialVersionUID有兩種生成方式:

一是默認(rèn)的1L,比如:private static final long serialVersionUID = 1L;

二是根據(jù)類名、接口名、成員方法及屬性等來生成一個(gè)64位的哈希字段。

如果程序沒有顯式的聲明serialVersionUID,那么程序?qū)⒂玫诙N實(shí)現(xiàn)。我們可以做一個(gè)實(shí)現(xiàn),還是用上述實(shí)現(xiàn)Serializable接口的例子。

我們先運(yùn)行一下程序,生成序列化文件tem.ser,在把“將對(duì)象序列化后保存到文件”這一段邏輯注釋掉,對(duì)Employee類增加一個(gè)test字段:

static class Employee implements Serializable {
  String name;
  int age;
  static String local = "earth";
  transient int ssh;
  String test;

  public void test() {
    System.out.println("this is test method!");
  }
}

這時(shí)候運(yùn)行的時(shí)候會(huì)報(bào)錯(cuò):

java.io.InvalidClassException: com.wangjun.othersOfJava.SerializeDemo$Employee; local class incompatible: stream classdesc serialVersionUID = 4506166831890198488, local class serialVersionUID = 785960679919880606
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1843)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2000)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
    at com.wangjun.othersOfJava.SerializeDemo.main(SerializeDemo.java:32)

因?yàn)槌绦虬l(fā)現(xiàn)取到的序列化文件的serialVersionUID和當(dāng)前的serialVersionUID不一樣。這個(gè)serialVersionUID是根據(jù)類名、接口名、成員方法及屬性等來生成一個(gè)64位的哈希字段,因?yàn)樵黾恿藅est字段,因此生成的serialVersionUID不一樣了。

接著,我們顯式的聲明serialVersionUID

static class Employee implements Serializable {
  private static final long serialVersionUID = 1L;
  String name;
  int age;
  static String local = "earth";
  transient int ssh;

  public void test() {
    System.out.println("this is test method!");
  }
}

將剛才注釋的代碼取消注釋,運(yùn)行一遍再注釋掉,并且新增字段test:

static class Employee implements Serializable {
  private static final long serialVersionUID = 1L;
  String name;
  int age;
  static String local = "earth";
  transient int ssh;
  String test;

  public void test() {
    System.out.println("this is test method!");
  }
}

再次運(yùn)行發(fā)現(xiàn)沒有報(bào)錯(cuò),運(yùn)行OK。這是因?yàn)槟泔@式聲明了serialVersionUID,序列化的serialVersionUID和目前的serialVersionUID一樣,因此會(huì)認(rèn)為是同一個(gè)版本的類。

你也可以將serialVersionUID改成2L,這個(gè)時(shí)候又會(huì)報(bào)錯(cuò)了。

參考:

https://www.cnblogs.com/duanx...

https://blog.csdn.net/fjndwy/...

https://blog.csdn.net/bigtree...

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68828.html

相關(guān)文章

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

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

    curlyCheng 評(píng)論0 收藏0
  • Java 對(duì)象列化

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

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

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

    fox_soyoung 評(píng)論0 收藏0
  • 淺談Java列化

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

    winterdawn 評(píng)論0 收藏0
  • java列化和反列化說起

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

    whlong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<