一、序列化 Java 序列化技術(shù)可以使你將一個對象的狀態(tài)寫入一個Byte 流里,并且可以從其它地方把該Byte流里的數(shù)據(jù)讀出來,重新構(gòu)造一個相同的對象。這種機(jī)制允許你將對象通過網(wǎng)絡(luò)進(jìn)行傳播,并可以隨時把對象持久化到數(shù)據(jù)庫、文件等系統(tǒng)里。Java的序列化機(jī)制是RMI、EJB等技術(shù)的技術(shù)基礎(chǔ)。
當(dāng)兩個進(jìn)程在進(jìn)行遠(yuǎn)程通信時,彼此可以發(fā)送各種類型的數(shù)據(jù)。無論是何種類型的數(shù)據(jù),都會以二進(jìn)制序列的形式在網(wǎng)絡(luò)上傳送。發(fā)送方需要把這個Java對象轉(zhuǎn)換為字節(jié)序列,才能在網(wǎng)絡(luò)上傳送;接收方則需要把字節(jié)序列再恢復(fù)為Java對象。
把Java對象轉(zhuǎn)換為字節(jié)序列的過程稱為對象的
序列化。
把字節(jié)序列恢復(fù)為Java對象的過程稱為對象的
反序列化。
1、序列化的用途 利用對象的序列化可以保存應(yīng)用程序的當(dāng)前工作狀態(tài),下次再啟動的時候?qū)⒆詣拥鼗謴?fù)到上次執(zhí)行的狀態(tài)。
對象的序列化主要有兩種用途:
(a) 把對象的字節(jié)序列永久地保存到硬盤上,通常存放在一個文件中;
(b) 在網(wǎng)絡(luò)上傳送對象的字節(jié)序列。
2、序列化的實現(xiàn)(1)JDK類庫中的序列化API java.io.ObjectOutputStream代表對象輸出流,它的writeObject(Object obj)方法可對參數(shù)指定的obj對象進(jìn)行序列化,把得到的字節(jié)序列寫到一個目標(biāo)輸出流中。
java.io.ObjectInputStream代表對象輸入流,它的readObject()方法從一個源輸入流中讀取字節(jié)序列,再把它們反序列化為一個對象,并將其返回。
只有實現(xiàn)了Serializable和Externalizable接口的類的對象才能被序列化。Externalizable接口繼承自Serializable接口,實現(xiàn)Externalizable接口的類完全由自身來控制序列化的行為,而僅實現(xiàn)Serializable接口的類可以采用默認(rèn)的序列化方式 。
(2)對象序列化與反序列化的過程 將需要被序列化的類實現(xiàn)Serializable接口,該接口沒有需要實現(xiàn)的方法,implementsSerializable只是為了標(biāo)注該對象是可被序列化的,然后使用一個輸出流(如:FileOutputStream)來構(gòu)造一個ObjectOutputStream(對象流)對象,接著,使用ObjectOutputStream對象的writeObject(Objectobj)方法就可以將參數(shù)為obj的對象寫出(即保存其狀態(tài)),要恢復(fù)的話則用輸入流。
對象序列化包括如下步驟: (a)創(chuàng)建一個對象輸出流,它可以包裝一個其他類型的目標(biāo)輸出流,如文件輸出流;
(b)通過對象輸出流的writeObject()方法寫對象。
對象反序列化的步驟如下:(a)創(chuàng)建一個對象輸入流,它可以包裝一個其他類型的源輸入流,如文件輸入流;
(b)通過對象輸入流的readObject()方法讀取對象。
下面讓我們來看一個對應(yīng)的例子,類的內(nèi)容如下:
import java.io.*; import java.util.Date; public class ObjectSaver { public static void main(String[] args) throws Exception { ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream("D:""objectFile.obj")); Customer customer = new Customer("阿蜜果", 24); out.writeObject("你好!"); out.writeObject(new Date()); out.writeObject(customer); out.writeInt(123); out.close(); ObjectInputStream in = new ObjectInputStream (new FileInputStream("D:""objectFile.obj")); System.out.println("obj1=" + (String) in.readObject()); System.out.println("obj2=" + (Date) in.readObject()); Customer obj3 = (Customer) in.readObject(); System.out.println("obj3=" + obj3); int obj4 = in.readInt(); System.out.println("obj4=" + obj4); in.close(); } } class Customer implements Serializable { private String name; private int age; public Customer(String name, int age) { this.name = name; this.age = age; } public String toString() { return "name=" + name + ", age=" + age; } } import java.io.*;import java.util.Date;public class ObjectSaver {public static void main(String[] args) throws Exception {ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:""objectFile.obj"));//序列化對象Customer customer = new Customer("阿蜜果", 24);out.writeObject("你好!");out.writeObject(new Date());out.writeObject(customer);out.writeInt(123); //寫入基本類型數(shù)據(jù)out.close();//反序列化對象ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:""objectFile.obj"));System.out.println("obj1=" + (String) in.readObject());System.out.println("obj2=" + (Date) in.readObject());Customer obj3 = (Customer) in.readObject();System.out.println("obj3=" + obj3);int obj4 = in.readInt();System.out.println("obj4=" + obj4);in.close();}}class Customer implements Serializable {private String name;private int age;public Customer(String name, int age) {this.name = name;this.age = age;}public String toString() {return "name=" + name + ", age=" + age;}}
輸出結(jié)果如下:
Java代碼
obj1=你好!obj2=Sat Sep 26 22:02:21 CST 2010obj3=name=阿蜜果, age=24obj4=123
因此例比較簡單,在此不再詳述。
3、serialVersionUID作用: 序列化時為了保持版本的兼容性,即在版本升級時反序列化仍保持對象的唯一性。
有兩種生成方式:
一個是默認(rèn)的1L,比如:
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
一個是根據(jù)類名、接口名、成員方法及屬性等來生成一個64位的哈希字段,比如:
private static final long serialVersionUID = xxxxL; private static final long serialVersionUID = xxxxL;
二、克隆 有時想得到對象的一個復(fù)制品,該復(fù)制品的實體是原對象實體的克隆。復(fù)制品實體的變化不會引起原對象實體發(fā)生變化,這樣的復(fù)制品稱為原對象實體的克隆對象或簡稱克隆。
1、淺復(fù)制(淺克隆) 概念:被復(fù)制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之,淺復(fù)制僅僅復(fù)制所考慮的對象,而不復(fù)制它所引用的對象。
方法:類implements Cloneable,然后重寫clone()方法,在clone()方法中調(diào)用super.clone()即可,沒有其他操作了
2、深復(fù)制(深克隆) 概念:被復(fù)制對象的所有變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量將指向被復(fù)制過的新對象,而不再是原有的那些被引用的對象。換言之,深復(fù)制把要復(fù)制的對象所引用的對象都復(fù)制了一遍
方法:(1)類implementsCloneable,然后重寫clone()方法,在clone()方法中調(diào)用super.clone(),然后還要對引用型變量所指的對象進(jìn)行克隆。(2)序列化:將該對象寫出到對象輸出流,那么用對象輸入流讀回的對象就是原對象的一個深度克隆。