欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

ava中怎么實現(xiàn)序列化與反序列化

這篇文章將為大家詳細講解有關(guān)ava中怎么實現(xiàn)序列化與反序列化,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

目前成都創(chuàng)新互聯(lián)已為上千多家的企業(yè)提供了網(wǎng)站建設、域名、網(wǎng)站空間、網(wǎng)站托管維護、企業(yè)網(wǎng)站設計、怒江州網(wǎng)站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

含義

序列化:對象寫入IO流中,實現(xiàn)對象變成文件。反序列化:把文件中的對象,進行恢復,恢復到內(nèi)存中,實現(xiàn)反序列化。意義:序列化的最大的意義在于實現(xiàn)對象可以跨主機進行傳輸,這些對象可以實現(xiàn)保存在磁盤中,并且脫離程序而獨立存在。

序列化需要實現(xiàn)一個接口

一個對象需要實現(xiàn)序列化,在這里,需要實現(xiàn)一個接口,這個接口為

java.io.Serializable

點開這個接口,可以看到定義的內(nèi)容如下

public interface Serializable {

}

進行序列化

把一個Java對象變成數(shù)組,在這里需要使用一個流,把一個Java對象寫入字節(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)) {

// 寫入int:

output.writeInt(12345);

// 寫入String:

output.writeUTF("Hello");

// 寫入Object:

output.writeObject(Double.valueOf(123.456));

}

System.out.println(Arrays.toString(buffer.toByteArray()));

}

}

在這里通過ObjectOutputStream類型,實現(xiàn)把數(shù)據(jù)寫入buffer中。

在這里寫入的是基本數(shù)據(jù)類型,這些基本數(shù)據(jù)類型為int,boolean,也可以寫入String,因為這些基本數(shù)據(jù)類型都實現(xiàn)了序列化的接口,所以寫入寫出的內(nèi)容都很大。

反序列化

ObjectInputStream 負責從一個字節(jié)流中讀取對象。代碼如下

try (ObjectInputStream input = new ObjectInputStream(...)) {

int n = input.readInt();

String s = input.readUTF();

Double d = (Double) input.readObject();

}

在這里,為了避免不讓Java類序列化時候,出現(xiàn)class類的不兼容。因為一臺主機上有class類,另外一臺主機上沒有該class類,此時,需要進行反序列化。同時標識版本,使用serialVersionUID  定義一個靜態(tài)的版本。例子如下

public class Person implements Serializable {

private static final long serialVersionUID = 2709425275741743919L;

}

原理

這里將會對Java序列化進行原理性的闡述。原理有點枯燥,客官可以跳過不看

一段序列化代碼

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輸出流對象

oos.writeObject(d); //向data1文件中寫入序列化數(shù)據(jù)data1類

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輸入流對象

data1 d = (data1)ois.readObject(); //從data1文件中反序列化出data1類數(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++打開以后是這樣

用十六進制查看

即,這些是序列化

源碼解析

序列化依靠的是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是往容器里寫兩個字節(jié),這里初始化寫入了4個字節(jié)(一個STREAM_MAGIC ,一個 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é)議以及說明序列化版本

開始序列化 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;

}

}

一般會直接調(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ù)對象的不同類型,按不同方法寫入序列化數(shù)據(jù),這里如果對象實現(xiàn)了Serializable接口,就調(diào)用writeOrdinaryObject()方法。

然后發(fā)現(xiàn)這個方法還傳入了一個desc,這是在此函數(shù)之前的一個for(;;)循環(huán)里,創(chuàng)建的用來描述該對象類信息的,ObjectStreamClass類。

然后看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(),寫入了一個字節(jié)的TC_OBJECT標志位(十六進制 73),然后調(diào)用writeClassDesc(desc),把之前生成的該類信息寫入,跟進看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()判斷類是否是動態(tài)代理類,沒了解過動態(tài)代理(先mark),這里因為不是動態(tài)代理類,所以會調(diào)用

writeNonProxyDesc(desc)

跟進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寫入了一個字節(jié)的TC_CLASSDESC(16進制 72)

然后下面一個判斷是true進入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()寫入了類名,這個writeUTF()函數(shù),在寫入十六進制類名前,會先寫入兩個字節(jié)的類名長度,

然后再調(diào)用writeLong,寫入序列化UID

然后下面有個判斷,會判斷類接口的實現(xiàn)方式,調(diào)用writeByte()寫入一個字節(jié)的標志位。

下面是所有標志位

/**

* 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寫入兩個字節(jié)的域長度(比如說有3個變量,就寫入 00 03 )

接下來是一個循環(huán),準備寫入這個類的變量名和它對應的變量類型了

每輪循環(huán):

writeByte寫入一個字節(jié)的變量類型;writeUTF()寫入變量名判斷是不是原始類型,即是不是對象不是原始類型(基本類型)的話,就調(diào)用writeTypeString()

這個writeTypeString(),如果是字符串,就會調(diào)用writeString()

而這個writeString()往往是這樣寫的,字符串長度(不是大小)小于兩個字節(jié),就先寫入一個字節(jié)的TC_STRING(16進制 74),然后調(diào)用writeUTF(),寫入一個signature,這好像跟jvm有關(guān),最后一般寫的是類似下面這串

74 00 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b

"翻譯"過來就是,字符串類型,占18個字節(jié)長度,變量名是

Ljava/lang/string;

而如果說,之前已經(jīng)聲明過上面這個對象,即前面有這串 74 00 12...3b

那就會調(diào)用writeHandle(),先寫入一個字節(jié)的TC_REFERENCE(16進制 71),然后調(diào)用writeInt()寫入 007e0000 + handle,這個handle是之前聲明過對象的位置,這里我還沒弄清除這個位置是怎么定位的,一般是00 01,也就是說 writeHandle(),一般寫入如下:

71 00 7e 00 XX這樣5個字節(jié)(最后這個00 XX 還不確定,等我再弄明白,一般是 00 01)

上面這些結(jié)束了,也就是我們寫完了writeNonProxy(),現(xiàn)在再次回到writeNonProxyDesc()

接下來繼續(xù)調(diào)用writeByte()寫入一個字節(jié)的TC_ENDBLOCKDATA(16進制 78),塊結(jié)束標志位

再調(diào)用writeCLassDesc(),參數(shù)是desc的父類,這里如果父類沒有實現(xiàn)序列化接口那就不會寫入,否則回到剛才writeNonProxyDesc那一步開始寫父類的類信息和變量信息(起始位72,終止位78),類似于一個遞歸調(diào)用,最后如果沒有實現(xiàn)了序列化接口的父類了,就會調(diào)用writeNull(),寫入一個字節(jié)的TC_NULL(16進制 70),表示沒對象了。

好了,總之writeClassDesc()這個遞歸調(diào)用完了之后,我們就回到了writeOrdinaryObject()

接下來調(diào)用writeSerialData(),準備寫入序列化數(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);

}

}

}

一個循環(huán),上限是類(包括父類)數(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();

}

}

}

}

先判斷是否是基本類型,是的話調(diào)用write直接寫入序列化數(shù)據(jù)

否則,獲取該類所有變量數(shù),開始循環(huán)

這個循環(huán)的每輪:

調(diào)用writeObject0()寫入變量,也就是說,根據(jù)變量類型,用相應方法寫入。

最后循環(huán)結(jié)束;

隨著所有變量的寫入,第一次循環(huán)也結(jié)束,writeSerialData()方法調(diào)用完畢,回到了writeOrdinaryObject(),執(zhí)行結(jié)束回到了writeObject0(),又回到了writeObject()。

關(guān)于ava中怎么實現(xiàn)序列化與反序列化就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

新聞標題:ava中怎么實現(xiàn)序列化與反序列化
URL鏈接:http://www.chinadenli.net/article2/jigdic.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設App設計響應式網(wǎng)站全網(wǎng)營銷推廣網(wǎng)站改版服務器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司