對(duì)象的序列化和反序列化
1)對(duì)象序列化,就是將Object對(duì)象轉(zhuǎn)換成byte序列,反之叫對(duì)象的反序列化。
2)序列化流(ObjectOutputStream),是字節(jié)的過濾流—— writeObject()方法
???? 反序列化流(ObjectInputStream)—— readObject()方法
3)序列化接口(Serializable)
對(duì)象必須實(shí)現(xiàn)序列化接口,才能進(jìn)行序列化,否則將出現(xiàn)異常。
注:這個(gè)接口,沒有任何方法,只是一個(gè)【標(biāo)準(zhǔn)】
一、最基本的序列化和反序列過程
序列化和反序列都是以O(shè)bject對(duì)象進(jìn)行操作的,這里通過一個(gè)簡單的案例來給大家演示一下對(duì)象序列化和反序列化的過程。
1、新建一個(gè)Student類(測試類)
注意:需要實(shí)現(xiàn)序列化接口的類才能進(jìn)行序列化操作?。?/span>
@SuppressWarnings("serial") public?class?Student?implements?Serializable{ ????private?String?stuno;//id ????private?String?stuna;//姓名 ????private?int?stuage;//年齡 ????public?String?getStuno()?{ ????????return?stuno; ????} ????public?void?setStuno(String?stuno)?{ ????????this.stuno?=?stuno; ????} ????public?String?getStuna()?{ ????????return?stuna; ????} ????public?void?setStuna(String?stuna)?{ ????????this.stuna?=?stuna; ????} ????public?Student()?{ ????????super(); ????????//?TODO?Auto-generated?constructor?stub ????} ????public?Student(String?stuno,?String?stuna,?int?stuage)?{ ????????super(); ????????this.stuno?=?stuno; ????????this.stuna?=?stuna; ????????this.stuage?=?stuage; ????} ????@Override ????public?String?toString()?{ ????????return?"Student?[stuno="?+?stuno?+?",?stuna="?+?stuna?+?",?stuage="?+?stuage?+?"]"; ????} ????public?int?getStuage()?{ ????????return?stuage; ????} ????public?void?setStuage(int?stuage)?{ ????????this.stuage?=?stuage; ????} }
2、將Student類的實(shí)例序列化成文件
基本操作步驟如下:
1)、指定序列化保存的文件
2)、構(gòu)造ObjectOutputStream類
3)、構(gòu)造一個(gè)Student類
4)、使用writeObject方法序列化
5)、使用close()方法關(guān)閉流
String?file="demo/obj.dat"; ????????//對(duì)象的序列化 ????????ObjectOutputStream?oos=new?ObjectOutputStream( ????????????????new?FileOutputStream(file)); ????????//把Student對(duì)象保存起來,就是對(duì)象的序列化 ????????Student?stu=new?Student("01","mike",18); ????????//使用writeObject方法序列化 ????????oos.writeObject(stu); ????????oos.close();
運(yùn)行結(jié)果:可以看到demo目錄下生成了obj.dat的序列化文件
3、將文件反序列化讀出Student類對(duì)象
基本操作步驟如下:
1)、指定反序列化的文件
2)、構(gòu)造ObjectInputStream類
3)、使用readObject方法反序列化
1)、使用close方法關(guān)閉流
String?file="demo/obj.dat"; ????????ObjectInputStream?ois?=new?ObjectInputStream( ????????????????new?FileInputStream(file)); ????????//使用readObject()方法序列化 ????????Student?stu=(Student)ois.readObject();//強(qiáng)制類型轉(zhuǎn)換 ????????System.out.println(stu); ????????ois.close();
運(yùn)行結(jié)果:
注意:在文件反序列化時(shí),readObject方法取出的對(duì)象默認(rèn)都是Object類型,必須強(qiáng)制轉(zhuǎn)換為相應(yīng)的類型。
二、transient及ArrayList源碼分析
在日常編程過程中,我們有時(shí)不希望一個(gè)類所有的元素都被編譯器序列化,這時(shí)該怎么辦呢?
Java提供了一個(gè)transient關(guān)鍵字來修飾我們不希望被jvm自動(dòng)序列化的元素。下面簡單來講解一下這個(gè)關(guān)鍵字。
transient 關(guān)鍵字:被transient修飾的元素,該元素不會(huì)進(jìn)行jvm默認(rèn)的序列化,但可以自己完成這個(gè)元素的序列化。
注意:
1)在以后的網(wǎng)絡(luò)編程中,如果有某些元素不需要傳輸,那就可以用transient修飾,來節(jié)省流量;對(duì)有效元素序列化,提高性能。
2)可以使用writeObject自己完成這個(gè)元素的序列化。
ArrayList就是用了此方法進(jìn)行了優(yōu)化操作。ArrayList最核心的容器Object[] elementData使用了transient修飾,但是在writeObject自己實(shí)現(xiàn)對(duì)elementData數(shù)組的序列化。只對(duì)數(shù)組中有效元素進(jìn)行序列化。readObject與之類似。
--------------自己序列化的方式---------------
在要序列化的類中加入兩個(gè)方法(這兩個(gè)方法都是從ArrayList源碼中提取出來的,比較特殊的兩個(gè)方法):
private?void?writeObject(java.io.ObjectOutputStream?s)?throws?java.io.IOException{ ????????s.defaultWriteObject();//把jvm能默認(rèn)序列化的元素進(jìn)行序列化操作 ????????s.writeInt(stuage);//自己完成被transient修飾的元素的序列化 ????} ????private?void?readObject(java.io.ObjectInputStream?s)?throws?java.io.IOException,ClassNotFoundException{ ????????s.defaultReadObject();//把jvm能默認(rèn)反序列化的元素進(jìn)行反序列化操作 ????????this.stuage=s.readInt();//自己完成stuage的反序列化操作 ????}
加入這兩個(gè)方法后,即使被transient修飾的元素也能像剛剛那樣進(jìn)行序列化和反序列化了,jvm會(huì)自動(dòng)使用這兩個(gè)方法幫助我們完成這動(dòng)作。
這里又有個(gè)問題,為什么還需要手動(dòng)去完成序列化和反序列化呢,有什么意義呢?
這個(gè)問題得再從ArrayList的源碼中去分析:
可以看出ArrayList源碼中自己序列化的目的:ArrayList底層為數(shù)組,自己序列化可以過濾數(shù)組中無效的元素,只序列化數(shù)組中有效的元素,從而提高性能。
因此,實(shí)際編程過程中我們可以根據(jù)需要來自己完成序列化以提高性能。
三、序列化中子父類構(gòu)造函數(shù)問題
在類的序列化和反序列化中,如果存在子類和父類的關(guān)系時(shí),序列化和反序列化的過程又是怎么樣的呢?
這里我寫一個(gè)測試類來測試子類和父類實(shí)現(xiàn)序列化和反序列化時(shí)構(gòu)造函數(shù)的實(shí)現(xiàn)變化。
public?static?void?main(String[]?args)?throws?IOException?{ ????????//?TODO?Auto-generated?method?stub ????????String?file="demo/foo.dat"; ????????ObjectOutputStream?oos=new?ObjectOutputStream( ????????????????new?FileOutputStream(file)); ????????Foo2?foo2?=new?Foo2(); ????????oos.writeObject(foo2); ????????oos.flush(); ????????oos.close(); ????} } class?Foo?implements?Serializable{ ????public?Foo(){ ????????System.out.println("foo"); ????} } class?Foo1?extends?Foo{ ????public?Foo1(){ ????????System.out.println("foo1"); ????} ???? } class?Foo2?extends?Foo1{ ????public?Foo2(){ ????????System.out.println("foo2"); ????} }
運(yùn)行結(jié)果:這是序列化時(shí)遞歸調(diào)用了父類的構(gòu)造函數(shù)
接來下看看反序列化時(shí),是否遞歸調(diào)用父類的構(gòu)造函數(shù)。
ObjectInputStream?ois=new?ObjectInputStream( new?FileInputStream(file)); Foo2?foo2=(Foo2)ois.readObject(); ois.close();
運(yùn)行結(jié)果:控制臺(tái)沒有任何輸出。
那么這個(gè)結(jié)果是否證明反序列化過程中父類的構(gòu)造函數(shù)就是始終不調(diào)用的呢?
然而不能證明?。?/span>
因?yàn)樵倏聪旅孢@個(gè)不同的測試?yán)樱?/p>
class?Bar?{ ????public?Bar(){ ????????System.out.println("bar"); ????} } class?Bar1?extends?Bar?implements?Serializable{ ????public?Bar1(){ ????????System.out.println("bar1"); ????} } class?Bar2?extends?Bar1{ ????public?Bar2(){ ????????System.out.println("bar2"); ????} }
我們用這個(gè)例子來測試序列化和反序列化。
序列化結(jié)果:
反序列化結(jié)果:沒實(shí)現(xiàn)序列化接口的父類被顯示調(diào)用構(gòu)造函數(shù)
【反序列化時(shí)】,向上遞歸調(diào)用構(gòu)造函數(shù)會(huì)從【可序列化的一級(jí)父類結(jié)束】。即誰實(shí)現(xiàn)了可序列化(包括繼承實(shí)現(xiàn)的),誰的構(gòu)造函數(shù)就不會(huì)調(diào)用。
總結(jié):
1)父類實(shí)現(xiàn)了serializable接口,子類繼承就可序列化。
子類在反序列化時(shí),父類實(shí)現(xiàn)了序列化接口,則不會(huì)遞歸調(diào)用其構(gòu)造函數(shù)。
2)父類未實(shí)現(xiàn)serializable接口,子類自行實(shí)現(xiàn)可序列化
子類在反序列化時(shí),父類沒有實(shí)現(xiàn)序列化接口,則會(huì)遞歸調(diào)用其構(gòu)造函數(shù)。
本文來自?java入門?欄目,歡迎學(xué)習(xí)!
Atas ialah kandungan terperinci Java之對(duì)象的序列化和反序列化. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Untuk mengendalikan transaksi JDBC dengan betul, anda mesti terlebih dahulu mematikan mod komit automatik, kemudian melakukan pelbagai operasi, dan akhirnya melakukan atau mengembalikan semula hasilnya; 1. Panggil Conn.SetAutOcommit (palsu) untuk memulakan transaksi; 2. Melaksanakan pelbagai operasi SQL, seperti memasukkan dan mengemaskini; 3. Panggil Conn.Commit () jika semua operasi berjaya, dan hubungi conn.rollback () jika pengecualian berlaku untuk memastikan konsistensi data; Pada masa yang sama, cuba-dengan-sumber harus digunakan untuk menguruskan sumber, mengendalikan pengecualian dengan betul dan menutup sambungan untuk mengelakkan kebocoran sambungan; Di samping itu, adalah disyorkan untuk menggunakan kolam sambungan dan menetapkan mata simpan untuk mencapai rollback separa, dan menyimpan urus niaga sesingkat mungkin untuk meningkatkan prestasi.

Gunakan kelas dalam pakej Java.Time untuk menggantikan kelas lama dan kelas kalendar; 2. Dapatkan tarikh dan masa semasa melalui LocalDate, LocalDateTime dan Tempatan Tempatan; 3. Buat tarikh dan masa tertentu menggunakan kaedah (); 4. Gunakan kaedah tambah/tolak untuk meningkatkan dan mengurangkan masa; 5. Gunakan zoneddatetime dan zonid untuk memproses zon waktu; 6. Format dan parse date string melalui DateTimeFormatter; 7. Gunakan segera untuk bersesuaian dengan jenis tarikh lama apabila perlu; pemprosesan tarikh di java moden harus memberi keutamaan untuk menggunakan java.timeapi, yang memberikan jelas, tidak berubah dan linear

Pra-formancetartuptimemoryusage, quarkusandmicronautleadduetocompile-timeprocessingandgraalvsupport, withquarkusoftenperforminglightbetterine serverless scenarios.tyvelopecosyste,

Koleksi Sampah Java (GC) adalah mekanisme yang secara automatik menguruskan ingatan, yang mengurangkan risiko kebocoran ingatan dengan menuntut semula objek yang tidak dapat dicapai. 1.GC menghakimi kebolehcapaian objek dari objek akar (seperti pembolehubah stack, benang aktif, medan statik, dan lain -lain), dan objek yang tidak dapat dicapai ditandakan sebagai sampah. 2. Berdasarkan algoritma penandaan tanda, tandakan semua objek yang dapat dicapai dan objek yang tidak ditandai. 3. Mengamalkan strategi pengumpulan generasi: Generasi Baru (Eden, S0, S1) sering melaksanakan MinorGC; Orang tua melakukan kurang tetapi mengambil masa lebih lama untuk melakukan MajorGC; Metaspace Stores Metadata kelas. 4. JVM menyediakan pelbagai peranti GC: SerialGC sesuai untuk aplikasi kecil; ParallelGC meningkatkan throughput; CMS mengurangkan

HTTP Log Middleware di GO boleh merakam kaedah permintaan, laluan, IP klien dan memakan masa. 1. Gunakan http.handlerfunc untuk membungkus pemproses, 2. Rekod waktu mula dan masa akhir sebelum dan selepas memanggil next.servehttp, 3. Dapatkan IP pelanggan sebenar melalui r.remoteaddr dan X-forward-for headers, 4. Gunakan log.printf untuk mengeluarkan log permintaan, 5. Kod sampel lengkap telah disahkan untuk dijalankan dan sesuai untuk memulakan projek kecil dan sederhana. Cadangan lanjutan termasuk menangkap kod status, menyokong log JSON dan meminta penjejakan ID.

Memilih jenis htmlinput yang betul dapat meningkatkan ketepatan data, meningkatkan pengalaman pengguna, dan meningkatkan kebolehgunaan. 1. Pilih jenis input yang sepadan mengikut jenis data, seperti teks, e -mel, tel, nombor dan tarikh, yang secara automatik boleh menyemak dan menyesuaikan diri dengan papan kekunci; 2. Gunakan HTML5 untuk menambah jenis baru seperti URL, Warna, Julat dan Carian, yang dapat memberikan kaedah interaksi yang lebih intuitif; 3. Gunakan pemegang tempat dan sifat -sifat yang diperlukan untuk meningkatkan kecekapan dan ketepatan pengisian bentuk, tetapi harus diperhatikan bahawa pemegang tempat tidak dapat menggantikan label.

GradleisthebetterChoiceFormostNewProjectSduetoitSsuperiorflexibility, Prestasi, danModernToolingSupport.1.Gradle'sGroovy/KOT lindslismoreconciseandexpressivethanmaven'sverbosexml.2.GradleOutPerformsMaveninBuildSpeedWithIncrementalcompilation, BuildCac

Defer digunakan untuk melaksanakan operasi tertentu sebelum fungsi pulangan, seperti sumber pembersihan; Parameter dinilai dengan serta-merta apabila menangguhkan, dan fungsi-fungsi dilaksanakan mengikut urutan terakhir (LIFO); 1. Pelbagai penahanan dilaksanakan dalam urutan terbalik pengisytiharan; 2. Biasanya digunakan untuk pembersihan yang selamat seperti penutupan fail; 3. Nilai pulangan yang dinamakan boleh diubah suai; 4. Ia akan dilaksanakan walaupun panik berlaku, sesuai untuk pemulihan; 5. Elakkan penyalahgunaan menangguhkan gelung untuk mengelakkan kebocoran sumber; Penggunaan yang betul boleh meningkatkan keselamatan kod dan kebolehbacaan.
