我們查看下ObjectOutputStream的writeObject方法
//final方法,不允許子類覆蓋
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;
}
}
如果要自定義這個序列化過程,則可以寫一個子類,集成ObjectOutputStream,然後覆蓋其兩個方法
protected ObjectOutputStream() throws IOException, SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
bout = null;
handles = null;
subs = null;
enableOverride = true;
debugInfoStack = null;
}
protected void writeObjectOverride(Object obj) throws IOException {
}
我們再看下具體的writeObject0方法:
private void writeObject0(Object obj, boolean unshared)
throws IOException
{
boolean oldMode = bout.setBlockDataMode(false);
depth++;
try {
// 先對obj實例的類信息進行序列化,
int h;
if ((obj = subs.lookup(obj)) == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {//可以自定義class類信息的序列化handler
writeHandle(h);
return;
} else if (obj instanceof Class) { //類信息序列化
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) { //類信息序列化,此時還包括serialVersionUID
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;
}
if (enableReplace) {
Object rep = replaceObject(obj);
if (rep != obj && rep != null) {
cl = rep.getClass();
desc = ObjectStreamClass.lookup(cl, true);
}
obj = rep;
}
// if object replaced, run through original checks a second time
//如果類信息被替換過,則需要進行第二次處理
if (obj != orig) {
subs.assign(orig, obj);
if (obj == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
} else if (obj instanceof Class) {
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
}
}
// 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) { //我們的bean需要實現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);
}
}
我們先簡單的看下如果是一個String,如何做這個序列化的過程:
private void writeString(String str, boolean unshared) throws IOException {
handles.assign(unshared ? null : str);
long utflen = bout.getUTFLength(str);
if (utflen <= 0xFFFF) {
bout.writeByte(TC_STRING);
bout.writeUTF(str, utflen);
} else {
bout.writeByte(TC_LONGSTRING);
bout.writeLongUTF(str, utflen);
}
}
bout的writeUTF方法:
void writeUTF(String s, long utflen) throws IOException {
if (utflen > 0xFFFFL) {
throw new UTFDataFormatException();
}
writeShort((int) utflen); //先寫入長度,
if (utflen == (long) s.length()) {
writeBytes(s); //然後寫入字節流
} else {
writeUTFBody(s);
}
}
很簡單,就是寫入一個字符串的一個字節的標示符,然後寫入字符串的字節流。
那麼再看看writeOrdinaryObject(obj, desc, unshared);如何對一個bean進行序列化
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(); //檢查下是否可以進行序列化,比如socket對象之類的,如果對象無法進行序列化,則拋出異常。
bout.writeByte(TC_OBJECT); //先寫入一個字節的類對象的標示符
writeClassDesc(desc, false); //序列化對象的class類信息
handles.assign(unshared ? null : obj); //保存類的seariableID跟對象的映射關係
if (desc.isExternalizable() && !desc.isProxy()) { //如果我們自定義了對象的序列化過程,則調用對象的writeExternalData方法。如果實現Externalizable
// /** true if represented class implements Externalizable */
// private boolean externalizable;
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc); //否則調用默認的序列化方法
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
然後我們先看看writeClassDesc(desc, false)的實現:
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()) { //如果是proxy對象,則調用該序列化機制 ,isProxy的判斷
//isProxy = Proxy.isProxyClass(cl); Returns true if and only if the specified class was dynamically generated to be a proxy class using the getProxyClass method or the newProxyInstance method.
writeProxyDesc(desc, unshared);
} else {
writeNonProxyDesc(desc, unshared);
}
}
/**
* Writes class descriptor representing a dynamic proxy class to stream.
*/
private void writeProxyDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
bout.writeByte(TC_PROXYCLASSDESC); //寫入代理對象的標示符
handles.assign(unshared ? null : desc);
Class cl = desc.forClass();
Class[] ifaces = cl.getInterfaces(); //如果是proxy對象,則寫入對象的interfaces的名稱
bout.writeInt(ifaces.length); //先寫入interface個數
for (int i = 0; i < ifaces.length; i++) {
bout.writeUTF(ifaces[i].getName()); //再寫入每個interface的名稱
}
bout.setBlockDataMode(true);
annotateProxyClass(cl);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA); //結束標籤
writeClassDesc(desc.getSuperDesc(), false);//遞歸寫入父類的序列化信息,因爲java是單繼承,
}
/**
* Writes class descriptor representing a standard (i.e., not a dynamic
* proxy) class to stream.
*/
private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
bout.writeByte(TC_CLASSDESC);//寫入class對象的標示符
handles.assign(unshared ? null : desc);
if (protocol == PROTOCOL_VERSION_1) { //如果非代理類對象的具體class信息,查看下面的方法
// do not invoke class descriptor write hook with old protocol
desc.writeNonProxy(this);
} else {
writeClassDescriptor(desc);
}
Class cl = desc.forClass();
bout.setBlockDataMode(true);
annotateClass(cl);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
writeClassDesc(desc.getSuperDesc(), false);//遞歸寫入父類的序列化信息,因爲java是單繼承,
}
writeClassDescriptor(desc)方法:
throws IOException
{
desc.writeNonProxy(this);
}
void writeNonProxy(ObjectOutputStream out) throws IOException {
out.writeUTF(name);//寫入類的名稱
out.writeLong(getSerialVersionUID());//寫入類的SerialVersionUID
byte flags = 0;
if (externalizable) {//是否實現externalizable接口
flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
int protocol = out.getProtocolVersion();
if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
flags |= ObjectStreamConstants.SC_BLOCK_DATA;
}
} else if (serializable) {//是否實現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); //遍歷寫入各個類的各個field字段類型名稱等信息
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i];
out.writeByte(f.getTypeCode()); //typecode參考ObjectStreamField.java類
out.writeUTF(f.getName());
if (!f.isPrimitive()) {
out.writeTypeString(f.getTypeString());
}
}
}
typecode:
case 'Z': type = Boolean.TYPE; break;
case 'B': type = Byte.TYPE; break;
case 'C': type = Character.TYPE; break;
case 'S': type = Short.TYPE; break;
case 'I': type = Integer.TYPE; break;
case 'J': type = Long.TYPE; break;
case 'F': type = Float.TYPE; break;
case 'D': type = Double.TYPE; break;
case 'L':
case '[': type = Object.class; break;
至此,對象obj的class相關信息已經全部寫入。
然後我們再查看具體寫入obj數據的過程
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()) { //Returns true if represented class is serializable (but not externalizable) and defines a conformant writeObject method. Otherwise, returns false.
Object oldObj = curObj;
ObjectStreamClass oldDesc = curDesc;
PutFieldImpl oldPut = curPut;
curObj = obj;
curDesc = slotDesc;
curPut = null;
if (extendedDebugInfo) {
debugInfoStack.push(
"custom writeObject data (class \"" +
slotDesc.getName() + "\")");
}
try {
bout.setBlockDataMode(true);
slotDesc.invokeWriteObject(obj, this);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
curObj = oldObj;
curDesc = oldDesc;
curPut = oldPut;
} else {
defaultWriteFields(obj, slotDesc); //寫入對象的字段數據
}
}
}
private void defaultWriteFields(Object obj, ObjectStreamClass desc)
throws IOException
{
// REMIND: perform conservative isInstance check here?
desc.checkDefaultSerialize();
int primDataSize = desc.getPrimDataSize(); //先寫入private field的數據
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++) { //寫入非private的數據
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()); //遞歸調用writeObject0寫入每個field的數據
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}
當然ObjectInputStream也類似。