《Java網(wǎng)絡程序設計》課件-第7章_第1頁
《Java網(wǎng)絡程序設計》課件-第7章_第2頁
《Java網(wǎng)絡程序設計》課件-第7章_第3頁
《Java網(wǎng)絡程序設計》課件-第7章_第4頁
《Java網(wǎng)絡程序設計》課件-第7章_第5頁
已閱讀5頁,還剩47頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第7章對象序列化

7.1對象序列化7.2序列化操作7.3定制序列化

7.1對?象?序?列?化

7.1.1序列化的概念

計算機軟件的主要工作是處理數(shù)據(jù)。在處理數(shù)據(jù)時,經(jīng)常會遇到需要處理一組相關的數(shù)據(jù),例如,要保存這樣一條聊天信息“張三:李四:你好”,這條信息中包括三個內容,即發(fā)信者、接收者和聊天內容,通常需要使用三個變量進行存儲。在C語言中使用結構體實現(xiàn)儲存一組相關的數(shù)據(jù),如例7-1所示。

【例7-1】

使用結構體存儲數(shù)據(jù)。

StructMessage{

charsender[10];

charreceiver[10];

charcontent[30];

}msg[20];

【例7-2】利用結構體存儲一組數(shù)據(jù),并保存在文件中或者從文件中讀取。

Filefp=File();

//存儲的方法

for(i=0;i<20;i++)

fwrite(&msg[i],sizeof(StructMessage),1,fp);

//讀取的方法

for(i=0;i<20;i++)

fread(&msg[i],sizeof(StructMessage),1,fp);

Java語言中,取消了結構體,除了基本數(shù)據(jù)類型都是對象。如果要存儲一組相關的數(shù)據(jù),就必須采用自定義相關類。

【例7-3】使用Java定義存儲消息的類。對比兩種語言對聊天消息的描述方法,其主要區(qū)別在于,使用Java語言描述方式不僅包含成員變量,而且包括了成員方法,從而實現(xiàn)了信息的封裝。

在Java語言中,處理數(shù)據(jù)均采用流的方式,其最大的特點就是數(shù)據(jù)的輸入和輸出都按順序進行。Java語言是面向對象的語言,除了字符串對象可以通過writeUTF()和readUTF()直接操作外,其他對象不能直接存儲和通過網(wǎng)絡發(fā)送。當需要對使用例7-3的類所定義的實例對象進行存儲或者發(fā)送時,就應該將該對象進行序列化操作,使其轉變?yōu)榱餍问?,然后才能實現(xiàn)存儲和通過網(wǎng)絡發(fā)送。序列化是一種用來處理對象流的機制,對象流是將對象的內容進行流化,然后將經(jīng)過流化后的對象進行讀/寫操作和用于網(wǎng)絡傳輸。發(fā)送端將對象序列化為流,接收端反序列化從數(shù)據(jù)流重新構造對象,保證了對象的完整性和可傳遞性。即,序列化的過程是將對象寫入字節(jié)流,反序列化的過程是從字節(jié)流中讀取對象。將對象狀態(tài)轉換成字節(jié)流之后,可以用java.io包中的各種字節(jié)流類將其保存到文件中,或者通過管道在線程之間傳輸,或者通過網(wǎng)絡連接將對象數(shù)據(jù)發(fā)送到另一主機。

序列化在網(wǎng)絡程序設計(如Socket、RMI(RemoteMethodInvocation)、JMS(JavaMessageService)、EJB(EnterpriseJavaBean))中有廣泛的應用。7.1.2序列化的實現(xiàn)

對象序列化是將攜帶信息的對象轉換為可以用于存儲或傳輸形式的過程。在序列化期間,對象將其當前狀態(tài)寫入到臨時或持久性存儲區(qū),然后,可以通過從存儲區(qū)中讀取或反序列化對象的狀態(tài),重新創(chuàng)建該對象。序列化分為兩大部分:序列化和反序列化,即對象序列化不僅要將對象轉換成字節(jié)表示,有時還要恢復對象。

序列化是這個過程的第一部分,將數(shù)據(jù)分解成字節(jié)流,以便存儲在文件中或在網(wǎng)絡上傳輸。反序列化就是打開字節(jié)流,按照被恢復數(shù)據(jù)的對象實例重構對象。這兩個過程結合起來,就可以輕松地存儲和傳輸對象數(shù)據(jù)。序列化的目的:

●?以某種存儲形式使自定義對象持久化;

●?將對象從一個地方傳遞到另一個地方;

●?使程序更具維護性。

Java序列化是基于TCP協(xié)議的,實現(xiàn)比較簡單,通常不需要編寫保存和恢復對象狀態(tài)的定制代碼。但是要求被序列化的類是實現(xiàn)了java.io.Serializable接口的,這樣就可以轉換成字節(jié)流或從字節(jié)流恢復,不需要在類中增加額外任何代碼。Serializable接口定義如圖7-1所示。圖7-1Serializable接口定義

在Serinalizable接口中未提供任何方法,即不存在需要被覆蓋的方法。通過implements實現(xiàn)Serializable接口的目的在于標識該對象是可被序列化的。

在Java語言中并不是任何個類都可被序列化。通常將用于存儲信息的類進行序列化,因為這些類所定義的對象是用于存儲和傳輸?shù)模鐚W生信息類、消息信息類。而用于執(zhí)行指令和操作的類是不用于序列化的,例如將學生信息儲存和讀取類、消息的發(fā)送和接收類。尤其要注意,涉及線程的類和與特定JVM有非常復雜關系的類,都不能進行序列化操作。序列化使其他代碼可以查看或修改那些不序列化便無法訪問的對象實例數(shù)據(jù)。確切地說,代碼執(zhí)行序列化需要特殊的權限,即指定了SerializationFormatter標志的Security?Permission。在默認策略下,通過Internet下載的代碼或Intranet代碼不會授予該權限;只有本地計算機上的代碼才被授予該權限。

通常,實現(xiàn)Serializable接口的類所聲明的對象實例中所有字段都會被序列化,這意味著數(shù)據(jù)會被表示為實例的序列化數(shù)據(jù)。這樣能夠解釋該格式的代碼有可能能夠確定這些數(shù)據(jù)的值,而不依賴于該成員的可訪問性。類似地,反序列化從序列化的表示形式中提取數(shù)據(jù),并直接設置對象狀態(tài),這也與可訪問性規(guī)則無關。7.1.3ObjectInputStream與ObjectOutputStream

為了將存儲于對象中的數(shù)據(jù)保存在磁盤文件或通過網(wǎng)絡發(fā)送等,需要使用基于對象的輸入/輸出流。java.io包提供兩個類用于序列化對象傳輸,分別是對象輸入類ObjectInput?Stream與對象輸出流類ObjectOutputStream。

ObjectInputStream用于從底層輸入流中讀取對象類型的數(shù)據(jù),ObjectOutputStream用于將對象類型的數(shù)據(jù)寫入到底層輸入流。ObjectInputStream與ObjectOutputStream類所讀/寫的對象必須實現(xiàn)了Serializable接口。對象中被transient和static修飾的成員變量不會被讀取和寫入?!?ObjectInputStream從字節(jié)流重構對象,實現(xiàn)反序列化過程。反序列化時,JVM用頭信息生成對象實例,然后將對象字節(jié)流中的數(shù)據(jù)復制到對象數(shù)據(jù)成員中。

●?ObjectOutputStream負責將對象寫入字節(jié)流,實現(xiàn)序列化過程,該序列化過程與字節(jié)流連接,包括對象類型和版本信息。

用一個輸出流(如FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,接著,使用ObjectOutputStream對象的writeObject(Objectobj)方法就可以將參數(shù)為obj的對象寫出(即保存其狀態(tài)),要恢復的話則用輸入流。當需要將數(shù)據(jù)存儲在本地磁盤時,在Java中需要使用ObjectOutputStream類,該類擴展DataOutput接口。writeObject()方法是最重要的方法,用于對象序列化。如果對象包含其他對象的引用,則writeObject()方法遞歸序列化這些對象。由于writeObject()可以序列化整組交叉引用的對象,因此,同一ObjectOutputStream實例可能不小心被請求序列化同一對象。每個ObjectOutputStream維護序列化的對象引用表,防止發(fā)送同一對象的多個拷貝。

【例7-4】

在文件tmp中保存兩個對象,其中一個是字符串“Today”,另一個是當前的日期。//

序列化

today's

?date

到一個文件中.

FileOutputStream

f

=

new

FileOutputStream("tmp");

ObjectOutputStream

s

=

new

ObjectOutputStream(f);

s.writeObject("Today");

s.writeObject(new

Date());

s.flush();

當需要將數(shù)據(jù)從本地磁盤讀取出時,在Java中需要使用ObjectInputStream類,該類擴展DataInput接口。readObject()為重要的方法,實現(xiàn)從字節(jié)流中反序列化對象。每次調用readObject()方法都返回流中下一個Object。對象字節(jié)流并不傳輸類的字節(jié)碼,而是包括類名及其簽名。readObject()收到對象時,JVM裝入頭中指定的類。如果找不到這個類,則readObject()拋出ClassNotFoundException。如果需要傳輸對象數(shù)據(jù)和字節(jié)碼,則可以用RMI框架。ObjectInputStream的其余方法用于定制反序列化過程。

【例7-5】從文件tmp中讀取數(shù)據(jù)對象。

//從文件中反序列化

string

對象和

date

對象

FileInputStream

in

=

new

FileInputStream(“tmp”);

ObjectInp

utStream

s

=

new

ObjectInputStream(in);

String

today

=

(String)s.readObject();

Date

date

=

(Date)s.readObject();

7.2序?列?化?操?作

7.2.1序列化存儲

通常,實現(xiàn)序列化接口的類是用于存儲和傳輸?shù)念悾糜诓僮鞯念愂遣贿M行序列化的。首先,通過代碼學習在Java中如何通過序列化實現(xiàn)聊天信息的儲存。在下面的例子中定義一個聊天信息類,該類用于存儲信息,需要實現(xiàn)Serializable接口。并且該類需要在存儲和讀取時都使用,通常將自定義信息類、存儲類和讀取類設計在一個包中,否則會出現(xiàn)無法找到類的異常發(fā)生。代碼注釋如下:

①第1行通常為了保證能夠順利地進行序列化和反序列化操作,聲明為Serializable接口的存儲類和實現(xiàn)操作類應在一個message包中,以保證訪問的路徑;

②第3行定義的存儲類實現(xiàn)了Serializable接口;

③第4~6行聲明了三個成員變量;

④第7~11行聲明了構造方法;

⑤第12~16行定義了輸出方法show()。

例7-6中定義的信息類需要實現(xiàn)Serializable接口,所以需要引用io類庫。在類中的成員變量有三個,分別記錄消息的發(fā)送者、接收者和內容。成員方法有兩個,一個是用于賦初值的構造方法Message(),另一個是用于輸出顯示的方法show()。接下來,定義將該類進行存儲操作的類,即進行序列化操作的類。該類中首先申明了兩個需要被存儲的信息對象,然后申明文件輸出對象,通過ObjectOutputStream.write

Object()方法,將信息對象保存到文件中。

【例7-7】

定義用于存儲學生信息的類,執(zhí)行序列化操作,保存數(shù)據(jù)至文件。

代碼注釋如下:

①第1行與實現(xiàn)序列化的存儲類在一個message包中;

②第9~10行使用Message類聲明了兩個被存儲對象;

③第12~13行聲明對象輸出流;

④第14~15行通過writeOjbect()輸出對象,實現(xiàn)序列化操作。

運行該程序,將在當前目錄下生成一個新的文件msgDB.dat,用于存儲信息。使用記事本軟件打開該文件,可以看到存儲的內容,如圖7-2所示。圖7-2msgDB.dat文件內容

【例7-8】

定義用于存儲信息的類,執(zhí)行反序列化操作,從文件中讀取數(shù)據(jù)還原成對象。

代碼注釋如下:

①第1行與實現(xiàn)序列化的存儲類在一個message包中;

②第9~10行聲明對象輸入流;

③第12~13行采用readObject()實現(xiàn)反序列化操作,因為讀取時默認類型為Object,所以需要進行一次強制類型轉換為需要的類對象;

④第16~17行輸出內容。

程序運行結果如圖7-3所示。圖7-3反序列化結果7.2.2序列化傳輸

序列化操作不僅可以在本地磁盤保存類數(shù)據(jù),也可以將對象用于網(wǎng)絡傳輸。首先,定義一個用于存儲消息的消息類,用于記錄消息發(fā)送者、消息接收者、消息內容,在這里直接利用了例7-6,注意Message類的包信息需要進行相應修改。另外分別編寫客戶端和服務器端程序。

【例7-9】實現(xiàn)客戶端,用于序列化對象,發(fā)送對象流。代碼注釋如下:

①第9行通過TCP連接指定的服務器localhost的8080端口;

②第10行套接字上獲得輸出流,使其作為對象輸出流的參數(shù);

③第11行準備要傳輸?shù)膶ο螅?/p>

④第12~13行通過writeObject()發(fā)送信息對象。

【例7-10】

實現(xiàn)服務器端,用于接收對象流,進行反序列化操作。代碼注釋如下:

①第10行啟動本地的TCP8080端口,監(jiān)聽客戶端的連接請求;

②第12行與客戶端實現(xiàn)連接;

③第13行獲得套接字的getInputStream(),使其作為ObjectInputStream的參數(shù);

④第15行獲得對象,并進行反序列化操作,還原為Message對象;

⑤第16~17行輸出結果。

服務器端接收序列化及反序列化操作運行結果如圖7-4所示。圖7-4服務器端運行結果從運行結果可見,服務器收到的信息對象直接輸出是不可讀的,除非該信息類中覆蓋了Object中的toString()方法。

7.3定?制?序?列?化

7.3.1序列化成員變量

在Java中類的成員變量可以是簡單數(shù)據(jù)類型,也可以是復雜數(shù)據(jù)類型,如字符串類類型、自定義類類型等。當某個類實現(xiàn)了序列化接口時,其未加transient和static修飾的成員變量一同被序列化。所以,當使用類類型定義成員變量時,要保證這些類是可以被序列化的,即實現(xiàn)了Serializable接口。如String類的定義中就聲明實現(xiàn)了Serializable接口,如圖7-5所示。圖7-5String類的定義當實現(xiàn)序列化的自定義類的成員變量中還包含了其他的自定義類對象時,就需要該成員變量實現(xiàn)序列化接口。

代碼注釋如下:

①第6行使用Detail類對象作為成員變量;

②第20~27行實現(xiàn)Detail類的定義,此時它未實現(xiàn)Serializable接口。

可以從以上代碼可以看出,新定義了Details類,用于存儲消息內容和發(fā)送時間,但是該類未實現(xiàn)序列化接口。在Message類中,采用Details類定義了一個details對象。在對此類進行編譯時,未出現(xiàn)任何錯誤提示。

在運行對象流發(fā)送端時將會拋出異常,提示Details類未實現(xiàn)Serializable接口,如圖7-6所示??梢娨粋€實現(xiàn)序列化接口中的成員變量如果是類對象,那么該類也必須實現(xiàn)了序列化接口,否則在運行時就會出現(xiàn)無法實現(xiàn)序列化操作的異常提示信息。圖7-6異常提示信息7.3.2定制序列化

對于一個正在運行的類對象來說,存在以下概念:

●?生命周期:從JVM提供一個對象所需要的資源,到釋放該對象資源為止,就是一個對象的生命周期。

●?短暫存儲:對象在內存中構建后,會隨著程序的運行和結束而改變和結束,這就是短暫存儲。在Java語言中,序列化過程中,使用transient關鍵字表示屬性或對象是短暫的。

●?永久存儲:對象被保存在永久設備中,這些永久設備包括文件、磁盤、數(shù)據(jù)庫等,該對象數(shù)據(jù)不會隨程序結束而消失。對象序列化是對象永久化的一種機制。序列化通常可以自動完成,但有時可能要對這個過程進行控制。對于任何可能包含重要的安全性數(shù)據(jù)的對象,應該使該對象不可序列化。如果它必須為可序列化的,也需要指定特定字段來保存不可序列化的重要數(shù)據(jù)。如果無法實現(xiàn)這一點,則應注意該數(shù)據(jù)會被公開給任何擁有序列化權限的代碼,并確保不讓任何惡意代碼獲得該權限。

Java在對類實現(xiàn)serializable接口時,可通過關鍵字static或transient為類中的數(shù)據(jù)成員變量進行定制,以實現(xiàn)保護特殊數(shù)據(jù)的目的。

將數(shù)據(jù)成員聲明為transient后,序列化過程就無法將其加進對象字節(jié)流中,也就沒有從transient數(shù)據(jù)成員發(fā)送的數(shù)據(jù)。后面數(shù)據(jù)反序列化時,要重建數(shù)據(jù)成員(因為它是類定義的一部分),但不包含任何數(shù)據(jù),因為這個數(shù)據(jù)成員不向流中寫入任何數(shù)據(jù)。

在本例的基礎上運行例

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論