日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java serializable用法_JAVA序列化Serializable及Externalizable区别详解

發(fā)布時(shí)間:2025/3/20 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java serializable用法_JAVA序列化Serializable及Externalizable区别详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

序列化簡介

Java 的對(duì)象序列化將那些實(shí)現(xiàn) Serializable 接口的對(duì)象轉(zhuǎn)換成一個(gè)字節(jié)序列,并能在之后將這個(gè)字節(jié)序列完全恢復(fù)為原來的對(duì)象。

這就意味著 Java 對(duì)象在網(wǎng)絡(luò)上的傳輸可以不依賴于當(dāng)前計(jì)算機(jī)的操作系統(tǒng),就可以將對(duì)象進(jìn)行傳遞,這也是Java跨平臺(tái)的一種體現(xiàn)。

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

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

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

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

先說結(jié)論

序列化有以下方式:

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

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

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

private void writeObject(ObjectOutputStream stream) throws IOException;

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

一、三種方式完成序列化

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

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

這種方式序列化的特征:

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

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

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

這種方式可以實(shí)現(xiàn)序列化的完全自定義:所有成員變量是否序列化都需要在 writeExternal()、readExternal()

方法中寫出;且可以完全自定義序列化方式(在 writerExternal()、readExternal()方法中)。當(dāng)然,實(shí)現(xiàn) Externalizable 接口必須要重寫這兩個(gè)方法。

這種方式序列化的特征:

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

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

3、 Externalizable 的替代方式進(jìn)行序列化

讓 ObjectOutputStream 和 ObjectInputStream 對(duì)象的 writeObject() 方法和 readObject() 方法調(diào)用我們編寫的這兩個(gè)方法。

如果想在這種方式中也調(diào)用原有默認(rèn)提供的方式,可以在 writeObject() 中調(diào)用: s.defaultWriteObject();,在 readObject() 中調(diào)用 s.defaultReadObject();。 這部分代碼可以查看 ArrayList 源碼。

二、測試代碼

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

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

主測試類 Dogs

public class Dogs {

public static void main(String[] args) throws Exception {

// 創(chuàng)建對(duì)象

System.out.println("--- 創(chuàng)建對(duì)象 ---");

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("--- 反序列化 ---");

// 反序列化 不會(huì)調(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 對(duì)象 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)造器運(yùn)行 ---");

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)造器運(yùn)行 ---");

this.name = name;

this.color = color;

System.out.println("Dogs2 : " + this);

}

// 省略get、set、toString方法

}

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

--- 創(chuàng)建對(duì)象 ---

Dog1 構(gòu)造器運(yùn)行 ---

Dog1 : Dog1{name='pidan', weight=4.0}

Dog2 構(gòu)造器運(yùn)行 ---

Dogs2 : Dog2{name='duanwu', color='black'}

--- 序列化 ---

--- 反序列化 ---

反序列化 o1 : Dog1{name='pidan', weight=4.0}

反序列化 o2 : Dog2{name='duanwu', color='black'}

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

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

主測試代碼:

public class Persons {

public static void main(String[] args) throws Exception {

// 創(chuàng)建對(duì)象

System.out.println("Init Objects");

Person1 p1 = new Person1();

Person2 p2 = new Person2();

// 存儲(chǔ)在磁盤上

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 對(duì)象: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 的運(yùn)行結(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 對(duì)象實(shí)現(xiàn)序列化

主測試類 Cats :

public class Cats {

public static void main(String[] args) throws Exception {

// 初始化對(duì)象

System.out.println("--- 初始化對(duì)象 ---");

Person person = new Person("01", "老王", 30);

Cat2 cat = new Cat2("fugui", person);

// 序列化

System.out.println("--- 序列化對(duì)象 ---");

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/cats.out"));

oos.writeObject(cat);

System.out.println("--- 反序列化對(duì)象 ---");

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/cats.out"));

cat = (Cat2) ois.readObject();

System.out.println("--- 反序列化對(duì)象后 ---");

System.out.println("cat : " + cat);

}

}

Externalizable 對(duì)象: Cat2 ;Serializable 對(duì)象: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();

}

}

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

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

--- 初始化對(duì)象 ---

--- Person 無參構(gòu)造器 ---

Person : Person{id='01', name='老王', age=30}

Cat2 有參構(gòu)造器 --->

Cat2 : Cat2{name='fugui', minion=Person{id='01', name='老王', age=30}}

--- 序列化對(duì)象 ---

--- Cat2:writeExternal ---

--- 反序列化對(duì)象 ---

Cat2 無參構(gòu)造器 --->

--- Cat2:readExternal ---

--- 反序列化對(duì)象后 ---

cat : Cat2{name='fugui', minion=Person{id='null', name='老王', age=30}}

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

注釋掉后的運(yùn)行結(jié)果:

--- 初始化對(duì)象 ---

--- Person 無參構(gòu)造器 ---

Person : Person{id='01', name='老王', age=30}

Cat2 有參構(gòu)造器 --->

Cat2 : Cat2{name='fugui', minion=Person{id='01', name='老王', age=30}}

--- 序列化對(duì)象 ---

--- Cat2:writeExternal ---

--- 反序列化對(duì)象 ---

Cat2 無參構(gòu)造器 --->

--- Cat2:readExternal ---

--- 反序列化對(duì)象后 ---

cat : Cat2{name='null', minion=null}

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

替代方式就是實(shí)現(xiàn) Serializable 接口,并且添加 writeObject(),readObject() 兩個(gè)方法注意這兩個(gè)方法必須有準(zhǔn)確的方法特征簽名,在這兩個(gè)方法中編寫自定義方式實(shí)現(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)建對(duì)象

System.out.println("--- 創(chuàng)建對(duì)象 ---");

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

}

}

運(yùn)行結(jié)果

--- 創(chuàng)建對(duì)象 ---

Mouse 有參構(gòu)造器 ---

Mouse : Mouse{name='zhizhi', i=2}

--- 序列化 ---

--- 這是自定義的writeExternal方法 ---

--- 反序列化 ---

--- 反序列化結(jié)果 ---

--- 這是自定義的readExternal方法 ---

zhizhi : Mouse{name='zhizhi', i=2}

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

與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的java serializable用法_JAVA序列化Serializable及Externalizable区别详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。