最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA序列化Serializable及Externalizable區(qū)別詳解

 更新時間:2020年07月15日 11:42:24   作者:像風(fēng)一樣無影無起  
這篇文章主要介紹了JAVA序列化Serializable及Externalizable區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

序列化簡介

Java 的對象序列化將那些實現(xiàn) Serializable 接口的對象轉(zhuǎn)換成一個字節(jié)序列,并能在之后將這個字節(jié)序列完全恢復(fù)為原來的對象。
這就意味著 Java 對象在網(wǎng)絡(luò)上的傳輸可以不依賴于當(dāng)前計算機的操作系統(tǒng),就可以將對象進行傳遞,這也是Java跨平臺的一種體現(xiàn)。

Java 對象的序列化主要支持兩種特性:

1、Java的遠程方法調(diào)用(Remote Method Invocation RMI);

2、對于 JavaBean 來說,序列化也是必須的。

要序列化一個對象,需要創(chuàng)建一個 OutputStream 對象,然后將其封裝在 ObjectOutputStream 對象中,再調(diào)用 writeObject() 方法就可以完成對象的序列化(也是在這一步進行序列化);反序列化(將一個序列還原為一個對象)就是該過程的反過程:創(chuàng)建一個 InputStream 對象,將其封裝在 ObjectInputStream 對象中,使用 readObject() 方法將序列反序列化為對象,當(dāng)然這是一個Object類型的對象,需要向下轉(zhuǎn)型為我們需要的類型(如果該類型不在本地,會導(dǎo)致反序列化失敗,ClassNotFoundException )。

先說結(jié)論

序列化有以下方式:

1、實現(xiàn) Serializable 接口:

2、實現(xiàn) Externalizable 接口,并重寫 writeExternal() readExternal() 方法;

3、(即下文中的 Externalizable 的替代方式進行序列化)如果不想實現(xiàn)Externalizable 接口,又想按照自己的規(guī)則進行序列化,可以實現(xiàn) Serializable 接口,并在該類中添加(添加,不是覆蓋、實現(xiàn))名為 writeExternal() readExternal() 方法,且這兩個方法必須為下面這兩個準(zhǔn)確的方法簽名:

private void writeObject(ObjectOutputStream stream) throws IOException;
private void readObject(ObjectInputStream stream) throws IOException,ClassNotFoundException;

一、三種方式完成序列化

1、實現(xiàn) Serializable 接口序列化

這種方式最為常用且常見,只需要對需要序列化的類實現(xiàn) Serializable 即可,對于不希望進行序列化的,可以使用 transient 關(guān)鍵詞進行修飾(即瞬時變量)。
這種方式序列化的特征:

1、 Serializable 接口僅僅是一個標(biāo)記接口,不包含任何方法;

2、對于Serializable對象來說,對象完全以它存儲的二進制位為基礎(chǔ)來構(gòu)造,(反序列化)不會調(diào)用構(gòu)造器。

2、實現(xiàn) Externalizable 接口序列化

這種方式可以實現(xiàn)序列化的完全自定義:所有成員變量是否序列化都需要在 writeExternal()、readExternal()
方法中寫出;且可以完全自定義序列化方式(在 writerExternal()、readExternal()方法中)。當(dāng)然,實現(xiàn) Externalizable 接口必須要重寫這兩個方法。
這種方式序列化的特征:

1、必須重寫 writerExternal()、readExternal()兩個方法,并在兩個方法中寫出所有需要序列化的成員變量;

2、對于 Externalizable對象來說,必須要有無參public構(gòu)造器,不然會報出 InvalidClassException 異常。

3、 Externalizable 的替代方式進行序列化

讓 ObjectOutputStream 和 ObjectInputStream 對象的 writeObject() 方法和 readObject() 方法調(diào)用我們編寫的這兩個方法。
如果想在這種方式中也調(diào)用原有默認(rèn)提供的方式,可以在 writeObject() 中調(diào)用: s.defaultWriteObject();,在 readObject() 中調(diào)用 s.defaultReadObject();。 這部分代碼可以查看 ArrayList 源碼。

二、測試代碼

1、 Serializable 對象反序列化,不調(diào)用任何構(gòu)造器

Serializable 對象反序列化不調(diào)用任何構(gòu)造器,包括默認(rèn)構(gòu)造器,整個對象都是從 InputStream 中取得數(shù)據(jù)恢復(fù)過來的

主測試類 Dogs

public class Dogs {
  public static void main(String[] args) throws Exception {
    // 創(chuàng)建對象
    System.out.println("--- 創(chuàng)建對象 ---");
    Dog1 d1 = new Dog1("pidan",4.0);
    Dog2 d2 = new Dog2("duanwu","black");
    // 序列化
    System.out.println("--- 序列化 ---");
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/dogs.out"));
    oos.writeObject(d1);
    oos.writeObject(d2);
    System.out.println("--- 反序列化 ---");
    // 反序列化 不會調(diào)用任何構(gòu)造器
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/dogs.out"));
    Dog1 o1 = (Dog1) ois.readObject();
    Dog2 o2 = (Dog2) ois.readObject();
    System.out.println("反序列化 o1 : " + o1);
    System.out.println("反序列化 o2 : " + o2);
  }
}

Serializable 對象 Dog1 Dog2 類

class Dog1 implements Serializable {
  private static final long serialVersionUID = -7101743601344663182L;

  private String name;
  private Double weight;

  public Dog1(String name, Double weight) {
    System.out.println("Dog1 構(gòu)造器運行 ---");
    this.name = name;
    this.weight = weight;
    System.out.println("Dog1 : " + this);
  }

  // 省略get、set、toString方法
}

public class Dog2 implements Serializable {

  private static final long serialVersionUID = -5462607652670703938L;

  private String name;
  private String color;

  public Dog2(String name, String color) {
    System.out.println("Dog2 構(gòu)造器運行 ---");
    this.name = name;
    this.color = color;
    System.out.println("Dogs2 : " + this);
  }

  // 省略get、set、toString方法
}

運行結(jié)果:

--- 創(chuàng)建對象 ---
Dog1 構(gòu)造器運行 ---
Dog1 : Dog1{name='pidan', weight=4.0}
Dog2 構(gòu)造器運行 ---
Dogs2 : Dog2{name='duanwu', color='black'}
--- 序列化 ---
--- 反序列化 ---
反序列化 o1 : Dog1{name='pidan', weight=4.0}
反序列化 o2 : Dog2{name='duanwu', color='black'}

再最后取出對象時,完全沒有調(diào)用到其任何構(gòu)造器。

2、無參構(gòu)造器對 Externalizable 對象序列化的影響

主測試代碼:

public class Persons {
  public static void main(String[] args) throws Exception {
    // 創(chuàng)建對象
    System.out.println("Init Objects");
    Person1 p1 = new Person1();
    Person2 p2 = new Person2();
    // 存儲在磁盤上
    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:/person.out"));
    os.writeObject(p1);
    os.writeObject(p2);
    os.flush();
    os.close();
    // 取出
    ObjectInputStream is = new ObjectInputStream(new FileInputStream("d:/person.out"));
    System.out.println("取出p1: ");
    p1 = (Person1) is.readObject();
    p2 = (Person2) is.readObject();
  }
}

Externalizable 對象:Perion1 Persion2

public class Person1 implements Externalizable {

  public Person1(){
    System.out.println("Person1 構(gòu)造器---");
  }

  @Override
  public void writeExternal(ObjectOutput out) throws IOException {
    System.out.println("Person1 writeExternal ---");
  }

  @Override
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    System.out.println("Person1 readExternal ---");
  }
}
class Person2 implements Externalizable{

  // 注意不是public
  Person2(){
    System.out.println("Person2 構(gòu)造器 ---");
  }
  @Override
  public void writeExternal(ObjectOutput out) throws IOException {
    System.out.println("Person2 writeExternal ---");
  }

  @Override
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    System.out.println("Person2 readExternal ---");
  }
}

Person2 默認(rèn)構(gòu)造器不是 public 的運行結(jié)果:

Init Objects
Person1 構(gòu)造器---
Person2 構(gòu)造器 ---
Person1 writeExternal ---
Person2 writeExternal ---
取出p1: 
Person1 構(gòu)造器---
Person1 readExternal ---
Exception in thread "main" java.io.InvalidClassException: ...serializableAndexternalizable.Person2; no valid constructor
	at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:169)
	at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:874)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2043)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
	at ...serializableAndexternalizable.Persons.main(Persons.java:29)

Process finished with exit code 1

將 Person2 構(gòu)造器改為 public 后:

Init Objects
Person1 構(gòu)造器---
Person2 構(gòu)造器 ---
Person1 writeExternal ---
Person2 writeExternal ---
取出p1:
Person1 構(gòu)造器---
Person1 readExternal ---
Person2 構(gòu)造器 ---
Person2 readExternal ---

3、使用 Externalizable 對象實現(xiàn)序列化

主測試類 Cats :

public class Cats {
  public static void main(String[] args) throws Exception {
    // 初始化對象
    System.out.println("--- 初始化對象 ---");
    Person person = new Person("01", "老王", 30);
    Cat2 cat = new Cat2("fugui", person);
    // 序列化
    System.out.println("--- 序列化對象 ---");
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/cats.out"));
    oos.writeObject(cat);
    System.out.println("--- 反序列化對象 ---");
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/cats.out"));
    cat = (Cat2) ois.readObject();
    System.out.println("--- 反序列化對象后 ---");
    System.out.println("cat : " + cat);
  }
}

Externalizable 對象: Cat2 ;Serializable 對象:Person :

public class Person implements Serializable {
  private static final long serialVersionUID = -822166081906894628L;
  private transient String id;
  private String name;
  private int age;

  public Person() {
    System.out.println("--- Person 無參構(gòu)造器 ---");
  }

  public Person(String id, String name, int age) {
    System.out.println("--- Person 無參構(gòu)造器 ---");
    this.id = id;
    this.name = name;
    this.age = age;
    System.out.println("Person : " + this);
  }

  // 省略get、set、toString方法
}

class Cat2 implements Externalizable {
  private static final long serialVersionUID = 1102930161606017855L;
  private String name;
  private Person minion;

  public Cat2() {
    System.out.println("Cat2 無參構(gòu)造器 --->");
  }

  public Cat2(String name, Person minion) {
    System.out.println("Cat2 有參構(gòu)造器 --->");
    this.name = name;
    this.minion = minion;
    System.out.println("Cat2 : " + this);
  }

  // 省略get、set、toString方法

  @Override
  public void writeExternal(ObjectOutput out) throws IOException {
    System.out.println("--- Cat2:writeExternal ---");
    // code1
    out.writeObject(this.minion);
    out.writeObject(this.name);
  }

  @Override
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    System.out.println("--- Cat2:readExternal ---");
    // code2
    this.minion = (Person) in.readObject();
    this.name = (String) in.readObject();
  }
}

運行結(jié)果:

可以注意到Person的成員變量id在使用了 transient 關(guān)鍵詞修飾后,就不再序列化該字段了。

--- 初始化對象 ---
--- Person 無參構(gòu)造器 ---
Person : Person{id='01', name='老王', age=30}
Cat2 有參構(gòu)造器 --->
Cat2 : Cat2{name='fugui', minion=Person{id='01', name='老王', age=30}}
--- 序列化對象 ---
--- Cat2:writeExternal ---
--- 反序列化對象 ---
Cat2 無參構(gòu)造器 --->
--- Cat2:readExternal ---
--- 反序列化對象后 ---
cat : Cat2{name='fugui', minion=Person{id='null', name='老王', age=30}}

如果將Cat2類中標(biāo)注的 code1 與 code2 代碼下面的兩行代碼均注釋掉,就不再可以序列化及反序列化了:
注釋掉后的運行結(jié)果:

--- 初始化對象 ---
--- Person 無參構(gòu)造器 ---
Person : Person{id='01', name='老王', age=30}
Cat2 有參構(gòu)造器 --->
Cat2 : Cat2{name='fugui', minion=Person{id='01', name='老王', age=30}}
--- 序列化對象 ---
--- Cat2:writeExternal ---
--- 反序列化對象 ---
Cat2 無參構(gòu)造器 --->
--- Cat2:readExternal ---
--- 反序列化對象后 ---
cat : Cat2{name='null', minion=null}

4、使用 Externalizable 對象替代方式實現(xiàn)序列化

替代方式就是實現(xiàn) Serializable 接口,并且添加 writeObject(),readObject() 兩個方法注意這兩個方法必須有準(zhǔn)確的方法特征簽名,在這兩個方法中編寫自定義方式實現(xiàn)序列化和反序列化。

class Mouse implements Serializable {
  private static final long serialVersionUID = -3278535893876444138L;
  private String name;
  private int i;

  public Mouse() {
    System.out.println("Mouse 無參構(gòu)造器 ---");
  }

  public Mouse(String name, int i) {
    System.out.println("Mouse 有參構(gòu)造器 ---");
    this.name = name;
    this.i = i;
    System.out.println("Mouse : " + this);
  }

  // 方法特征簽名必須完全一致
  private void writeObject(ObjectOutputStream stream) throws IOException {
//    stream.defaultWriteObject();// 可以選擇執(zhí)行默認(rèn)的writeObject()
    System.out.println("--- 這是自定義的writeExternal方法 ---");
    stream.writeObject(this.name);
    stream.writeInt(this.i);
  }

  // 方法特征簽名必須完全一致
  private void readObject(ObjectInputStream stream) throws IOException,ClassNotFoundException {
//    stream.defaultReadObject(); // 可以選擇執(zhí)行默認(rèn)的readObject()
    System.out.println("--- 這是自定義的readExternal方法 ---");
    this.name = (String)stream.readObject();
    this.i = stream.readInt();
  }

  // 省略get、set、toString方法
}

主測試類:

public class Mouses {
  public static void main(String[] args) throws Exception {
    // 創(chuàng)建對象
    System.out.println("--- 創(chuàng)建對象 ---");
    Mouse m1 = new Mouse("zhizhi", 2);
    // 序列化
    System.out.println("--- 序列化 ---");
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/mouse.out"));
    oos.writeObject(m1);
    // 反序列化
    System.out.println("--- 反序列化 ---");
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/mouse.out"));
    // 反序列化結(jié)果
    System.out.println("--- 反序列化結(jié)果 ---");
    m1 = (Mouse) ois.readObject();
    System.out.println(" zhizhi : " + m1);
  }
}

運行結(jié)果

--- 創(chuàng)建對象 ---
Mouse 有參構(gòu)造器 ---
Mouse : Mouse{name='zhizhi', i=2}
--- 序列化 ---
--- 這是自定義的writeExternal方法 ---
--- 反序列化 ---
--- 反序列化結(jié)果 ---
--- 這是自定義的readExternal方法 ---
zhizhi : Mouse{name='zhizhi', i=2}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Thread類interrupt interrupted及isInterrupted區(qū)別

    Thread類interrupt interrupted及isInterrupted區(qū)別

    這篇文章主要為大家介紹了Thread類interrupt interrupted及isInterrupted區(qū)別,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • SpringBoot@Profile注解和Spring?EL(多環(huán)境注入)

    SpringBoot@Profile注解和Spring?EL(多環(huán)境注入)

    為了方便, Spring還提供了 Profile機制, 使我們可以很方便地實現(xiàn)各個環(huán)境之間的切換,在使用DI來依賴注入的時候,能夠根據(jù)@profile標(biāo)明的環(huán)境,將注入符合當(dāng)前運行環(huán)境的相應(yīng)的bean,本文通過示例代碼介紹SpringBoot@Profile注解和Spring?EL,需要的朋友可以參考下
    2024-02-02
  • 一文詳解mybatis二級緩存執(zhí)行流程

    一文詳解mybatis二級緩存執(zhí)行流程

    本文主要詳細介紹了mybatis二級緩存執(zhí)行流程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考價值,感興趣的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2024-02-02
  • Spring Boot的Profile配置詳解

    Spring Boot的Profile配置詳解

    本篇文章主要介紹了Spring Boot的Profile配置詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Spring的@Scheduled 如何動態(tài)更新cron表達式

    Spring的@Scheduled 如何動態(tài)更新cron表達式

    這篇文章主要介紹了Spring的@Scheduled 如何動態(tài)更新cron表達式的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • spring cloud gateway跨域全局CORS配置方式

    spring cloud gateway跨域全局CORS配置方式

    這篇文章主要介紹了spring cloud gateway跨域全局CORS配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 詳解設(shè)計模式在Spring中的應(yīng)用(9種)

    詳解設(shè)計模式在Spring中的應(yīng)用(9種)

    這篇文章主要介紹了詳解設(shè)計模式在Spring中的應(yīng)用(9種),詳細的介紹了這9種模式在項目中的應(yīng)用,具有一定的參考價值,感興趣的可以了解一下
    2019-04-04
  • 教你用Springboot實現(xiàn)攔截器獲取header內(nèi)容

    教你用Springboot實現(xiàn)攔截器獲取header內(nèi)容

    項目中遇到一個需求,對接上游系統(tǒng)是涉及到需要增加請求頭,請求頭的信息是動態(tài)獲取的,需要動態(tài)從下游拿到之后轉(zhuǎn)給上游,文中非常詳細的介紹了該需求的實現(xiàn),需要的朋友可以參考下
    2021-05-05
  • Java實例講解文件上傳與跨域問題

    Java實例講解文件上傳與跨域問題

    這篇文章主要介紹了Java文件上傳與跨域問題,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Mac配置 maven以及環(huán)境變量設(shè)置方式

    Mac配置 maven以及環(huán)境變量設(shè)置方式

    這篇文章主要介紹了Mac配置 maven以及環(huán)境變量設(shè)置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08

最新評論

盐池县| 岗巴县| 孙吴县| 平南县| 山东| 寿阳县| 铜山县| 宣武区| 抚宁县| 获嘉县| 明溪县| 广河县| 游戏| 酒泉市| 长泰县| 札达县| 奈曼旗| 张家界市| 绍兴县| 沙坪坝区| 沁源县| 望江县| 囊谦县| 阿克苏市| 蒙自县| 武山县| 丽水市| 全南县| 虞城县| 沾化县| 六枝特区| 肃南| 四子王旗| 额济纳旗| 阜平县| 吉木萨尔县| 阳信县| 通州市| 和静县| 定远县| 永靖县|