十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶(hù) + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專(zhuān)業(yè)推廣+無(wú)憂(yōu)售后,網(wǎng)站問(wèn)題一站解決
這篇文章將為大家詳細(xì)講解有關(guān)ava中怎么實(shí)現(xiàn)序列化與反序列化,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

目前成都創(chuàng)新互聯(lián)已為上千多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站托管維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、怒江州網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶(hù)導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶(hù)和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
含義
序列化:對(duì)象寫(xiě)入IO流中,實(shí)現(xiàn)對(duì)象變成文件。反序列化:把文件中的對(duì)象,進(jìn)行恢復(fù),恢復(fù)到內(nèi)存中,實(shí)現(xiàn)反序列化。意義:序列化的最大的意義在于實(shí)現(xiàn)對(duì)象可以跨主機(jī)進(jìn)行傳輸,這些對(duì)象可以實(shí)現(xiàn)保存在磁盤(pán)中,并且脫離程序而獨(dú)立存在。
序列化需要實(shí)現(xiàn)一個(gè)接口
一個(gè)對(duì)象需要實(shí)現(xiàn)序列化,在這里,需要實(shí)現(xiàn)一個(gè)接口,這個(gè)接口為
java.io.Serializable
點(diǎn)開(kāi)這個(gè)接口,可以看到定義的內(nèi)容如下
public interface Serializable {
}
進(jìn)行序列化
把一個(gè)Java對(duì)象變成數(shù)組,在這里需要使用一個(gè)流,把一個(gè)Java對(duì)象寫(xiě)入字節(jié)流。其代碼如下
import java.io.*;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (ObjectOutputStream output = new ObjectOutputStream(buffer)) {
// 寫(xiě)入int:
output.writeInt(12345);
// 寫(xiě)入String:
output.writeUTF("Hello");
// 寫(xiě)入Object:
output.writeObject(Double.valueOf(123.456));
}
System.out.println(Arrays.toString(buffer.toByteArray()));
}
}
在這里通過(guò)ObjectOutputStream類(lèi)型,實(shí)現(xiàn)把數(shù)據(jù)寫(xiě)入buffer中。
在這里寫(xiě)入的是基本數(shù)據(jù)類(lèi)型,這些基本數(shù)據(jù)類(lèi)型為int,boolean,也可以寫(xiě)入String,因?yàn)檫@些基本數(shù)據(jù)類(lèi)型都實(shí)現(xiàn)了序列化的接口,所以寫(xiě)入寫(xiě)出的內(nèi)容都很大。
反序列化
ObjectInputStream 負(fù)責(zé)從一個(gè)字節(jié)流中讀取對(duì)象。代碼如下
try (ObjectInputStream input = new ObjectInputStream(...)) {
int n = input.readInt();
String s = input.readUTF();
Double d = (Double) input.readObject();
}
在這里,為了避免不讓Java類(lèi)序列化時(shí)候,出現(xiàn)class類(lèi)的不兼容。因?yàn)橐慌_(tái)主機(jī)上有class類(lèi),另外一臺(tái)主機(jī)上沒(méi)有該class類(lèi),此時(shí),需要進(jìn)行反序列化。同時(shí)標(biāo)識(shí)版本,使用serialVersionUID 定義一個(gè)靜態(tài)的版本。例子如下
public class Person implements Serializable {
private static final long serialVersionUID = 2709425275741743919L;
}
原理
這里將會(huì)對(duì)Java序列化進(jìn)行原理性的闡述。原理有點(diǎn)枯燥,客官可以跳過(guò)不看
一段序列化代碼
public class SerializeTest {
public void serialize() throws Exception{
data1 d = new data1();
d.setId(1036);
d.setName("data1");
d.setPwd("pwd1");
d.setPwd2("pwd2");
FileOutputStream fos = new FileOutputStream("d:/project/serial/data1");
ObjectOutputStream oos = new ObjectOutputStream(fos); //創(chuàng)建Object輸出流對(duì)象
oos.writeObject(d); //向data1文件中寫(xiě)入序列化數(shù)據(jù)data1類(lèi)
fos.close();
oos.close();
System.out.println("序列化完成");
}
public data1 deSerialize() throws Exception{
FileInputStream fis = new FileInputStream("d:/project/serial/data1");
ObjectInputStream ois = new ObjectInputStream(fis); //創(chuàng)建Object輸入流對(duì)象
data1 d = (data1)ois.readObject(); //從data1文件中反序列化出data1類(lèi)數(shù)據(jù)
ois.close();
fis.close();
return d;
}
public static void main(String[] args) throws Exception{
SerializeTest s = new SerializeTest();
s.serialize();
data1 d = s.deSerialize();
System.out.println("id:"+d.getId());
System.out.println("name:"+d.getName());
System.out.println("pwd:"+d.getPwd());
}
}
執(zhí)行序列化以后,用notdpad++打開(kāi)以后是這樣
用十六進(jìn)制查看
即,這些是序列化
源碼解析
序列化依靠的是ObjectOutputStream。構(gòu)造參數(shù)
public ObjectOutputStream(OutputStream out) throws IOException {
verifySubclass();
bout = new BlockDataOutputStream(out);
handles = new HandleTable(10, (float) 3.00);
subs = new ReplaceTable(10, (float) 3.00);
enableOverride = false;
writeStreamHeader();
bout.setBlockDataMode(true);
if (extendedDebugInfo) {
debugInfoStack = new DebugTraceInfoStack();
} else {
debugInfoStack = null;
}
}
其writeStreamHeader代碼如下
protected void writeStreamHeader() throws IOException {
bout.writeShort(STREAM_MAGIC);
bout.writeShort(STREAM_VERSION);
}
writeShort是往容器里寫(xiě)兩個(gè)字節(jié),這里初始化寫(xiě)入了4個(gè)字節(jié)(一個(gè)STREAM_MAGIC ,一個(gè) STREAM_VERSION)
/**
* Magic number that is written to the stream header.
*/
final static short STREAM_MAGIC = (short)0xaced;
/**
* Version number that is written to the stream header.
*/
final static short STREAM_VERSION = 5;
即 ac ed 00 05,表示聲明使用序列化協(xié)議以及說(shuō)明序列化版本
開(kāi)始序列化 writeObject()
public final void writeObject(Object obj) throws IOException {
if (enableOverride) {
writeObjectOverride(obj);
return;
}
try {
writeObject0(obj, false);
} catch (IOException ex) {
if (depth == 0) {
writeFatalException(ex);
}
throw ex;
}
}
一般會(huì)直接調(diào)用writeObject0()
private void writeObject0(Object obj, boolean unshared)
throws IOException
{
boolean oldMode = bout.setBlockDataMode(false);
depth++;
try {
// handle previously written and non-replaceable objects
int h;
...省略代碼
if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
}
// check for replacement object
Object orig = obj;
Class cl = obj.getClass();
ObjectStreamClass desc;
for (;;) {
// REMIND: skip this check for strings/arrays?
Class repCl;
desc = ObjectStreamClass.lookup(cl, true);
if (!desc.hasWriteReplaceMethod() ||
(obj = desc.invokeWriteReplace(obj)) == null ||
(repCl = obj.getClass()) == cl)
{
break;
}
cl = repCl;
}
// remaining cases
if (obj instanceof String) {
writeString((String) obj, unshared);
} else if (cl.isArray()) {
writeArray(obj, desc, unshared);
} else if (obj instanceof Enum) {
writeEnum((Enum) obj, desc, unshared);
} else if (obj instanceof Serializable) {
writeOrdinaryObject(obj, desc, unshared);
} else {
if (extendedDebugInfo) {
throw new NotSerializableException(
cl.getName() + "n" + debugInfoStack.toString());
} else {
throw new NotSerializableException(cl.getName());
}
}
} finally {
depth--;
bout.setBlockDataMode(oldMode);
}
}
后面那些判斷,容易看出,根據(jù)對(duì)象的不同類(lèi)型,按不同方法寫(xiě)入序列化數(shù)據(jù),這里如果對(duì)象實(shí)現(xiàn)了Serializable接口,就調(diào)用writeOrdinaryObject()方法。
然后發(fā)現(xiàn)這個(gè)方法還傳入了一個(gè)desc,這是在此函數(shù)之前的一個(gè)for(;;)循環(huán)里,創(chuàng)建的用來(lái)描述該對(duì)象類(lèi)信息的,ObjectStreamClass類(lèi)。
然后看writeOrdinaryObject()
private void writeOrdinaryObject(Object obj,
ObjectStreamClass desc,
boolean unshared)
throws IOException
{
if (extendedDebugInfo) {
debugInfoStack.push(
(depth == 1 ? "root " : "") + "object (class "" +
obj.getClass().getName() + "", " + obj.toString() + ")");
}
try {
desc.checkSerialize();
bout.writeByte(TC_OBJECT);
writeClassDesc(desc, false);
handles.assign(unshared ? null : obj);
if (desc.isExternalizable() && !desc.isProxy()) {
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc);
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
先是writeByte(),寫(xiě)入了一個(gè)字節(jié)的TC_OBJECT標(biāo)志位(十六進(jìn)制 73),然后調(diào)用writeClassDesc(desc),把之前生成的該類(lèi)信息寫(xiě)入,跟進(jìn)看writeClassDesc()
private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
int handle;
if (desc == null) {
writeNull();
} else if (!unshared && (handle = handles.lookup(desc)) != -1) {
writeHandle(handle);
} else if (desc.isProxy()) {
writeProxyDesc(desc, unshared);
} else {
writeNonProxyDesc(desc, unshared);
}
}
isProxy()判斷類(lèi)是否是動(dòng)態(tài)代理類(lèi),沒(méi)了解過(guò)動(dòng)態(tài)代理(先mark),這里因?yàn)椴皇莿?dòng)態(tài)代理類(lèi),所以會(huì)調(diào)用
writeNonProxyDesc(desc)
跟進(jìn)writeNonProxyDesc(desc)
private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
bout.writeByte(TC_CLASSDESC);
handles.assign(unshared ? null : desc);
if (protocol == PROTOCOL_VERSION_1) {
// do not invoke class descriptor write hook with old protocol
desc.writeNonProxy(this);
} else {
writeClassDescriptor(desc);
}
Class cl = desc.forClass();
bout.setBlockDataMode(true);
if (cl != null && isCustomSubclass()) {
ReflectUtil.checkPackageAccess(cl);
}
annotateClass(cl);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
writeClassDesc(desc.getSuperDesc(), false);
}
發(fā)現(xiàn)writeByte寫(xiě)入了一個(gè)字節(jié)的TC_CLASSDESC(16進(jìn)制 72)
然后下面一個(gè)判斷是true進(jìn)入writeNonProxy()
writeNonProxy()
void writeNonProxy(ObjectOutputStream out) throws IOException {
out.writeUTF(name);
out.writeLong(getSerialVersionUID());
byte flags = 0;
if (externalizable) {
flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
int protocol = out.getProtocolVersion();
if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
flags |= ObjectStreamConstants.SC_BLOCK_DATA;
}
} else if (serializable) {
flags |= ObjectStreamConstants.SC_SERIALIZABLE;
}
if (hasWriteObjectData) {
flags |= ObjectStreamConstants.SC_WRITE_METHOD;
}
if (isEnum) {
flags |= ObjectStreamConstants.SC_ENUM;
}
out.writeByte(flags);
out.writeShort(fields.length);
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i];
out.writeByte(f.getTypeCode());
out.writeUTF(f.getName());
if (!f.isPrimitive()) {
out.writeTypeString(f.getTypeString());
}
}
}
調(diào)用writeUTF()寫(xiě)入了類(lèi)名,這個(gè)writeUTF()函數(shù),在寫(xiě)入十六進(jìn)制類(lèi)名前,會(huì)先寫(xiě)入兩個(gè)字節(jié)的類(lèi)名長(zhǎng)度,
然后再調(diào)用writeLong,寫(xiě)入序列化UID
然后下面有個(gè)判斷,會(huì)判斷類(lèi)接口的實(shí)現(xiàn)方式,調(diào)用writeByte()寫(xiě)入一個(gè)字節(jié)的標(biāo)志位。
下面是所有標(biāo)志位
/**
* Bit mask for ObjectStreamClass flag. Indicates Externalizable data
* written in Block Data mode.
* Added for PROTOCOL_VERSION_2.
*
* @see #PROTOCOL_VERSION_2
* @since 1.2
*/
final static byte SC_BLOCK_DATA = 0x08;
/**
* Bit mask for ObjectStreamClass flag. Indicates class is Serializable.
*/
final static byte SC_SERIALIZABLE = 0x02;
/**
* Bit mask for ObjectStreamClass flag. Indicates class is Externalizable.
*/
final static byte SC_EXTERNALIZABLE = 0x04;
/**
* Bit mask for ObjectStreamClass flag. Indicates class is an enum type.
* @since 1.5
*/
final static byte SC_ENUM = 0x10;
然后調(diào)用writeShort寫(xiě)入兩個(gè)字節(jié)的域長(zhǎng)度(比如說(shuō)有3個(gè)變量,就寫(xiě)入 00 03 )
接下來(lái)是一個(gè)循環(huán),準(zhǔn)備寫(xiě)入這個(gè)類(lèi)的變量名和它對(duì)應(yīng)的變量類(lèi)型了
每輪循環(huán):
writeByte寫(xiě)入一個(gè)字節(jié)的變量類(lèi)型;writeUTF()寫(xiě)入變量名判斷是不是原始類(lèi)型,即是不是對(duì)象不是原始類(lèi)型(基本類(lèi)型)的話(huà),就調(diào)用writeTypeString()
這個(gè)writeTypeString(),如果是字符串,就會(huì)調(diào)用writeString()
而這個(gè)writeString()往往是這樣寫(xiě)的,字符串長(zhǎng)度(不是大小)小于兩個(gè)字節(jié),就先寫(xiě)入一個(gè)字節(jié)的TC_STRING(16進(jìn)制 74),然后調(diào)用writeUTF(),寫(xiě)入一個(gè)signature,這好像跟jvm有關(guān),最后一般寫(xiě)的是類(lèi)似下面這串
74 00 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b
"翻譯"過(guò)來(lái)就是,字符串類(lèi)型,占18個(gè)字節(jié)長(zhǎng)度,變量名是
Ljava/lang/string;
而如果說(shuō),之前已經(jīng)聲明過(guò)上面這個(gè)對(duì)象,即前面有這串 74 00 12...3b
那就會(huì)調(diào)用writeHandle(),先寫(xiě)入一個(gè)字節(jié)的TC_REFERENCE(16進(jìn)制 71),然后調(diào)用writeInt()寫(xiě)入 007e0000 + handle,這個(gè)handle是之前聲明過(guò)對(duì)象的位置,這里我還沒(méi)弄清除這個(gè)位置是怎么定位的,一般是00 01,也就是說(shuō) writeHandle(),一般寫(xiě)入如下:
71 00 7e 00 XX這樣5個(gè)字節(jié)(最后這個(gè)00 XX 還不確定,等我再弄明白,一般是 00 01)
上面這些結(jié)束了,也就是我們寫(xiě)完了writeNonProxy(),現(xiàn)在再次回到writeNonProxyDesc()
接下來(lái)繼續(xù)調(diào)用writeByte()寫(xiě)入一個(gè)字節(jié)的TC_ENDBLOCKDATA(16進(jìn)制 78),塊結(jié)束標(biāo)志位
再調(diào)用writeCLassDesc(),參數(shù)是desc的父類(lèi),這里如果父類(lèi)沒(méi)有實(shí)現(xiàn)序列化接口那就不會(huì)寫(xiě)入,否則回到剛才writeNonProxyDesc那一步開(kāi)始寫(xiě)父類(lèi)的類(lèi)信息和變量信息(起始位72,終止位78),類(lèi)似于一個(gè)遞歸調(diào)用,最后如果沒(méi)有實(shí)現(xiàn)了序列化接口的父類(lèi)了,就會(huì)調(diào)用writeNull(),寫(xiě)入一個(gè)字節(jié)的TC_NULL(16進(jìn)制 70),表示沒(méi)對(duì)象了。
好了,總之writeClassDesc()這個(gè)遞歸調(diào)用完了之后,我們就回到了writeOrdinaryObject()
接下來(lái)調(diào)用writeSerialData(),準(zhǔn)備寫(xiě)入序列化數(shù)據(jù)
writeSerialData()
private void writeSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slotDesc.hasWriteObjectMethod()) {
PutFieldImpl oldPut = curPut;
curPut = null;
SerialCallbackContext oldContext = curContext;
if (extendedDebugInfo) {
debugInfoStack.push(
"custom writeObject data (class "" +
slotDesc.getName() + "")");
}
try {
curContext = new SerialCallbackContext(obj, slotDesc);
bout.setBlockDataMode(true);
slotDesc.invokeWriteObject(obj, this);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
} finally {
curContext.setUsed();
curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
curPut = oldPut;
} else {
defaultWriteFields(obj, slotDesc);
}
}
}
一個(gè)循環(huán),上限是類(lèi)(包括父類(lèi))數(shù)量
每輪:
調(diào)用defaultWriteFields()
defaultWriteFields()
private void defaultWriteFields(Object obj, ObjectStreamClass desc)
throws IOException
{
Class cl = desc.forClass();
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}
desc.checkDefaultSerialize();
int primDataSize = desc.getPrimDataSize();
if (primVals == null || primVals.length < primDataSize) {
primVals = new byte[primDataSize];
}
desc.getPrimFieldValues(obj, primVals);
bout.write(primVals, 0, primDataSize, false);
ObjectStreamField[] fields = desc.getFields(false);
Object[] objVals = new Object[desc.getNumObjFields()];
int numPrimFields = fields.length - objVals.length;
desc.getObjFieldValues(obj, objVals);
for (int i = 0; i < objVals.length; i++) {
if (extendedDebugInfo) {
debugInfoStack.push(
"field (class "" + desc.getName() + "", name: "" +
fields[numPrimFields + i].getName() + "", type: "" +
fields[numPrimFields + i].getType() + "")");
}
try {
writeObject0(objVals[i],
fields[numPrimFields + i].isUnshared());
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}
先判斷是否是基本類(lèi)型,是的話(huà)調(diào)用write直接寫(xiě)入序列化數(shù)據(jù)
否則,獲取該類(lèi)所有變量數(shù),開(kāi)始循環(huán)
這個(gè)循環(huán)的每輪:
調(diào)用writeObject0()寫(xiě)入變量,也就是說(shuō),根據(jù)變量類(lèi)型,用相應(yīng)方法寫(xiě)入。
最后循環(huán)結(jié)束;
隨著所有變量的寫(xiě)入,第一次循環(huán)也結(jié)束,writeSerialData()方法調(diào)用完畢,回到了writeOrdinaryObject(),執(zhí)行結(jié)束回到了writeObject0(),又回到了writeObject()。
關(guān)于ava中怎么實(shí)現(xiàn)序列化與反序列化就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。