【JDK源码分析】01-对象序列化ObjectOutputStream
2018-03-10 00:00
651 查看
上一篇文章提到反序列化枚举类仍是单例,而普通类对象不是单例,下面我们先分析一下序列化过程,序列化就是调用ObjectOutStream的对象的writeObject方法。我们先看一下序列化涉及的比较重要的一个ObjectStreamClass,JDK中的描述是:类的序列化描述符。它包含类描述信息,字段的描述信息和 serialVersionUID。可以使用 lookup 方法找到/创建在此 Java VM 中加载的具体类的 ObjectStreamClass。ObjectOutputStream在序列化一个对象的时候就把这个对象的类描述信息序列化的,要想获得一个可序列化类的描述信息那我们就可以调用ObjectStreamClass的lookup方法:public static ObjectStreamClass lookup(Class<?> cl) {
return lookup(cl, false);
}
// REMIND: synchronize instead of relying on volatile?
if (suid == null) {
suid = AccessController.doPrivileged(
new PrivilegedAction<Long>() {
public Long run() {
return computeDefaultSUID(cl);
}
}
);
}
return suid.longValue();
}若果类中没有定义[ANY-ACCESS-MODIFIER static final long serialVersionUID]字段,则通过以上方法根据Class对象相关信息分配一个值。下面是ObjectStreamField定义,一目了然。public class ObjectStreamField
implements Comparable<Object>
{
/** field name */
private final String name;
/** canonical JVM signature of field type */
private final String signature;
/** field type (Object.class if unknown non-primitive type) */
private final Class<?> type;
/** whether or not to (de)serialize field values as unshared */
private final boolean
12507
unshared;
/** corresponding reflective field object, if any */
private final Field field;
/** offset of field value in enclosing field group */
private int offset = 0;我们看一下ObjectOutpupStream构造方法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();//此处首先往输出流中写入magic和版本号
bout.setBlockDataMode(true);
if (extendedDebugInfo) {
debugInfoStack = new DebugTraceInfoStack();
} else {
debugInfoStack = null;
}
}
之后我们就可以调用writeObject()方法写入对象了,实际调用了writeObject0()方法public final void writeObject(Object obj) throws IOException {
if (enableOverride) {//默认false
writeObjectOverride(obj);
return;
}
try {
writeObject0(obj, false);//此方法实际调用writeObject0()方法
} catch (IOException ex) {
if (depth == 0) {
writeFatalException(ex);
}
throw ex;
}
}然后来到writeObject0()方法
注释1⃣️获取序列对象的类信息ObjectStreamClass,此类上面已经介绍了,核心类之一。注释2⃣️到注释5⃣️分别是序列化不同数据类型,我们分析一下序列化枚举writeEnum()和序列化writeOrdinaryObject()。private void writeEnum(Enum<?> en,
ObjectStreamClass desc,
boolean unshared)
throws IOException
{
bout.writeByte(TC_ENUM);//第五个字节代表数据类型,这里是枚举
ObjectStreamClass sdesc = desc.getSuperDesc();//父类的描述信息
writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);//首先写入类的描述信息,然后写入父类的描述信息
handles.assign(unshared ? null : en);//缓存一下,不是重点
writeString(en.name(), false);//写入枚举name属性
}上面代码比较重要的就是写入类的描述信息writeClassDesc()方法和写入枚举值writeString()方法。
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);//枚举类型走这
}
}然后调用writeNonProxyDesc()方法: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);//然后写入父类的描述信息
}
out.writeUTF(name);//写入类名
out.writeLong(getSerialVersionUID());//上面分析过枚举为0
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); //综合标志--实现了哪种序列化接口有writeObjectData()方法是枚举类型吗
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());
}
}
}所以综上写入一个枚举类型的顺序为 magic(short)->version(short)->TC_ENUM(byte)->TC_CLASSDESC(byte)->className(String)->serialVersionUID(long)->flags(byte)->TC_ENDBLOCKDATA(byte)->父类Enum的类描述信息->TC_STRING或TC_LONGSTRING(byte)->枚举名称(String)。
写一个测试类:public enum Gender {
MAN,WOMAN;
}
private static void testSeriableEnum() throws IOException {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(Gender.MAN);
System.out.println(baos.toString());
}结果如下:
以上就是枚举序列化的全部,枚举的序列化还是清晰明了的,先枚举本身然后枚举父类最后枚举名称。
对象的序列化与枚举最大的区别在于字段的序列化,我们看一下序列对象调用的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();
}
}
}与枚举一样先写本类的描述信息,然后一直沿着最先类写到第一个没有实现序列化接口的祖先类(不含)描述信息,不同的是在writeNonProxy()方法中枚举没有成员字段可写因为fields为长度为0的空数组,而一般类则会依次写入字段类的描述信息,先基本数据类型后对象类型。之后掉用writeSerialData()方法,在这个方法中如果该类没有实现前面分析ObjectStreamClass对象保存的writeObjet()方法则会调用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()方法序列化此成员变量的对象,一个递归过程。
writeObject0(objVals[i],
fields[numPrimFields + i].isUnshared());
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}序列化对象字段的过程就是如果该字段是基本数据类型直接序列化,对象类型将该成员变量引用的对象再次当作一个可序列化对象传入writeObject0方法的参数中是一个递归的过程。综上,一般类的序列化过程就是首先将该类的描述信息序列化,然后将其中所有可序列化的成员变量递归的方式序列化(成员变量是基本数据类型直接序列化,一般类类型递归序列化)。
写个例子测试一下:public class Human{
public Human(String a){}
}
public class Person extends Human implements Serializable{
public String xyz="lmn";
public String name;
public int age=55;
public int length=66;
public int width=77;
public Person(String name) {
super(name);
this.name=name;
}
}
private static void testSeriableEnum() throws IOException {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
// oos.writeObject(Gender.MAN);
oos.writeObject(new Person("abc"));
System.out.println(baos.toString());
}运行结果:
注意因为Human没有Serializable接口,所以序列化结果不包含Human的相关信息。
return lookup(cl, false);
}
static ObjectStreamClass lookup(Class<?> cl, boolean all) { if (!(all || Serializable.class.isAssignableFrom(cl))) { return null; } processQueue(Caches.localDescsQueue, Caches.localDescs);//处理已被GC回收的Class对象所对应的ObjectStreamClass对象 WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue); Reference<?> ref = Caches.localDescs.get(key);//先尝试从缓存中找到cl对应的ObjectStreamClass对象 Object entry = null; if (ref != null) { entry = ref.get();//如果存在则取出 } EntryFuture future = null; if (entry == null) {//如果不存在则创建一个Future作为后续生成ObjectStreamClass实例的容器 EntryFuture newEntry = new EntryFuture(); Reference<?> newRef = new SoftReference<>(newEntry); do { if (ref != null) {//移除旧的不引用任何对象的Reference Caches.localDescs.remove(key, ref); } ref = Caches.localDescs.putIfAbsent(key, newRef);//新建cl对应的引用,此时引用的只是一个空Future if (ref != null) { entry = ref.get(); } } while (ref != null && entry == null); if (entry == null) { future = newEntry; } } //取得缓存中的直接返回 if (entry instanceof ObjectStreamClass) { // check common case first return (ObjectStreamClass) entry; } if (entry instanceof EntryFuture) { future = (EntryFuture) entry; if (future.getOwner() == Thread.currentThread()) { /* * Handle nested call situation described by 4803747: waiting * for future value to be set by a lookup() call further up the * stack will result in deadlock, so calculate and set the * future value here instead. */ entry = null; } else { entry = future.get(); } } if (entry == null) { try { entry = new ObjectStreamClass(cl);//这是重点下面着重分析一下 } catch (Throwable th) { entry = th; } if (future.set(entry)) { Caches.localDescs.put(key, new SoftReference<Object>(entry));//更新Future为ObjectStreamClass } else { // nested lookup call already set future entry = future.get(); } } if (entry instanceof ObjectStreamClass) { return (ObjectStreamClass) entry; } else if (entry instanceof RuntimeException) { throw (RuntimeException) entry; } else if (entry instanceof Error) { throw (Error) entry; } else { throw new InternalError("unexpected entry: " + entry); } }
private ObjectStreamClass(final Class<?> cl) { this.cl = cl; name = cl.getName();//类名 isProxy = Proxy.isProxyClass(cl);//是否是JDK动态代理产生的对象类 isEnum = Enum.class.isAssignableFrom(cl);//是否枚举累 serializable = Serializable.class.isAssignableFrom(cl);//时候实现了序列化接口 externalizable = Externalizable.class.isAssignableFrom(cl);//是否实现了Externalozable接口 Class<?> superCl = cl.getSuperclass(); superDesc = (superCl != null) ? lookup(superCl, false) : null;//记录父类的描述信息 localDesc = this;//保存本实例引用 if (serializable) {//实现了序列化接口的 AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { if (isEnum) { suid = Long.valueOf(0);//枚举类固定serialVersionUID为0 fields = NO_FIELDS;//枚举字段设为空 return null; } if (cl.isArray()) { fields = NO_FIELDS;//数组.class的类描述字段设为空 return null; } suid = getDeclaredSUID(cl);//若不是枚举和数组读取类的静态final的长整型字段serialVersionUID,若没明确指定该字段值则通过getSerialVersionUID()方法分配一个值 try { fields = getSerialFields(cl);//获取类中定义的私有静态final的ObjectStreamField数组serialPersistentFields,它指定了需要序列化的字段,如果没有指定则默认使用非静态瞬时的成员字段 computeFieldOffsets(); } catch (InvalidClassException e) { serializeEx = deserializeEx = new ExceptionInfo(e.classname, e.getMessage()); fields = NO_FIELDS; } if (externalizable) { cons = getExternalizableConstructor(cl); } else { cons = getSerializableConstructor(cl);//获取最近没有实现序列化接口的祖先类的无参构造方法要是public或protected或与父类在一个package中,否则返回null writeObjectMethod = getPrivateMethod(cl, "writeObject",//保存类的private void writeObject(ObjectOutputStream os)方法 new Class<?>[] { ObjectOutputStream.class }, Void.TYPE); readObjectMethod = getPrivateMethod(cl, "readObject",//保存类的private void readObject(ObjectInputStream is)方法 new Class<?>[] { ObjectInputStream.class }, Void.TYPE); readObjectNoDataMethod = getPrivateMethod( //保存类的private void readObjectNoData()方法 cl, "readObjectNoData", null, Void.TYPE); hasWriteObjectData = (writeObjectMethod != null); } domains = getProtectionDomains(cons, cl); writeReplaceMethod = getInheritableMethod( //保存非static abstract Object writeReplace()方法,可继承父类的但不能是私有 cl, "writeReplace", null, Object.class); readResolveMethod = getInheritableMethod( //保存非static abstract Object readResolve()方法 cl, "readResolve", null, Object.class); return null; } }); } else { //没有实现Serializable接口的类serialVersionUID设为0且类描述字段数组置为空数组 suid = Long.valueOf(0); fields = NO_FIELDS; } try {//字段信息反射器,包含了可序列化的成员字段,基本类型成员数量等信息 fieldRefl = getReflector(fields, this); } catch (InvalidClassException ex) { // field mismatches impossible when matching local fields vs. self throw new InternalError(ex); } if (deserializeEx == null) { if (isEnum) { deserializeEx = new ExceptionInfo(name, "enum type"); } else if (cons == null) {//注意这个地方也很重要,如果没有cons反序列化的时候会抛出no valid constructor deserializeEx = new ExceptionInfo(name, "no valid constructor"); } } for (int i = 0; i < fields.length; i++) { if (fields[i].getField() == null) { defaultSerializeEx = new ExceptionInfo( name, "unmatched serializable field(s) declared"); } } initialized = true; }有一点需要注意的是deserializeEx,反序列化时会判断不为空的话抛出他描述的异常信息。譬如没有一个合适的午餐构造函数就会抛no valid constructor,所以一般都要提供一个public的午餐构造方法以便序列化,这个下篇文章会再次提及。rpublic long getSerialVersionUID() {
// REMIND: synchronize instead of relying on volatile?
if (suid == null) {
suid = AccessController.doPrivileged(
new PrivilegedAction<Long>() {
public Long run() {
return computeDefaultSUID(cl);
}
}
);
}
return suid.longValue();
}若果类中没有定义[ANY-ACCESS-MODIFIER static final long serialVersionUID]字段,则通过以上方法根据Class对象相关信息分配一个值。下面是ObjectStreamField定义,一目了然。public class ObjectStreamField
implements Comparable<Object>
{
/** field name */
private final String name;
/** canonical JVM signature of field type */
private final String signature;
/** field type (Object.class if unknown non-primitive type) */
private final Class<?> type;
/** whether or not to (de)serialize field values as unshared */
private final boolean
12507
unshared;
/** corresponding reflective field object, if any */
private final Field field;
/** offset of field value in enclosing field group */
private int offset = 0;我们看一下ObjectOutpupStream构造方法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();//此处首先往输出流中写入magic和版本号
bout.setBlockDataMode(true);
if (extendedDebugInfo) {
debugInfoStack = new DebugTraceInfoStack();
} else {
debugInfoStack = null;
}
}
protected void writeStreamHeader() throws IOException { bout.writeShort(STREAM_MAGIC);// bout.writeShort(STREAM_VERSION); }在构造方法中首先调用writeStreanHeader()方法往输出流中写入magic表明这是一个jdk序列化文件格式以及版本号。
之后我们就可以调用writeObject()方法写入对象了,实际调用了writeObject0()方法public final void writeObject(Object obj) throws IOException {
if (enableOverride) {//默认false
writeObjectOverride(obj);
return;
}
try {
writeObject0(obj, false);//此方法实际调用writeObject0()方法
} catch (IOException ex) {
if (depth == 0) {
writeFatalException(ex);
}
throw ex;
}
}然后来到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 = subs.lookup(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; } // 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);//1⃣️.获取累的描述信息 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);//2⃣️序列化字符串 } else if (cl.isArray()) { writeArray(obj, desc, unshared);//3⃣️序列化数组 } else if (obj instanceof Enum) { writeEnum((Enum<?>) obj, desc, unshared);//4⃣️序列化枚举 } else if (obj instanceof Serializable) { writeOrdinaryObject(obj, desc, unshared);//5⃣️序列化实现了Serializable接口的对象 } else { if (extendedDebugInfo) { throw new NotSerializableException( cl.getName() + "\n" + debugInfoStack.toString()); } else { throw new NotSerializableException(cl.getName()); } } } finally { depth--; bout.setBlockDataMode(oldMode); } }上面的方法有点长,核心代码就是以上添加的五行注释,
注释1⃣️获取序列对象的类信息ObjectStreamClass,此类上面已经介绍了,核心类之一。注释2⃣️到注释5⃣️分别是序列化不同数据类型,我们分析一下序列化枚举writeEnum()和序列化writeOrdinaryObject()。private void writeEnum(Enum<?> en,
ObjectStreamClass desc,
boolean unshared)
throws IOException
{
bout.writeByte(TC_ENUM);//第五个字节代表数据类型,这里是枚举
ObjectStreamClass sdesc = desc.getSuperDesc();//父类的描述信息
writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);//首先写入类的描述信息,然后写入父类的描述信息
handles.assign(unshared ? null : en);//缓存一下,不是重点
writeString(en.name(), false);//写入枚举name属性
}上面代码比较重要的就是写入类的描述信息writeClassDesc()方法和写入枚举值writeString()方法。
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);//枚举类型走这
}
}然后调用writeNonProxyDesc()方法: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);//然后写入父类的描述信息
}
protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException { desc.writeNonProxy(this); }写入类的描述信息就是调用ObjectOutputStream的writeNonProxy()方法。void writeNonProxy(ObjectOutputStream out) throws IOException {
out.writeUTF(name);//写入类名
out.writeLong(getSerialVersionUID());//上面分析过枚举为0
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); //综合标志--实现了哪种序列化接口有writeObjectData()方法是枚举类型吗
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());
}
}
}所以综上写入一个枚举类型的顺序为 magic(short)->version(short)->TC_ENUM(byte)->TC_CLASSDESC(byte)->className(String)->serialVersionUID(long)->flags(byte)->TC_ENDBLOCKDATA(byte)->父类Enum的类描述信息->TC_STRING或TC_LONGSTRING(byte)->枚举名称(String)。
写一个测试类:public enum Gender {
MAN,WOMAN;
}
private static void testSeriableEnum() throws IOException {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(Gender.MAN);
System.out.println(baos.toString());
}结果如下:
以上就是枚举序列化的全部,枚举的序列化还是清晰明了的,先枚举本身然后枚举父类最后枚举名称。
对象的序列化与枚举最大的区别在于字段的序列化,我们看一下序列对象调用的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();
}
}
}与枚举一样先写本类的描述信息,然后一直沿着最先类写到第一个没有实现序列化接口的祖先类(不含)描述信息,不同的是在writeNonProxy()方法中枚举没有成员字段可写因为fields为长度为0的空数组,而一般类则会依次写入字段类的描述信息,先基本数据类型后对象类型。之后掉用writeSerialData()方法,在这个方法中如果该类没有实现前面分析ObjectStreamClass对象保存的writeObjet()方法则会调用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()方法序列化此成员变量的对象,一个递归过程。
writeObject0(objVals[i],
fields[numPrimFields + i].isUnshared());
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}序列化对象字段的过程就是如果该字段是基本数据类型直接序列化,对象类型将该成员变量引用的对象再次当作一个可序列化对象传入writeObject0方法的参数中是一个递归的过程。综上,一般类的序列化过程就是首先将该类的描述信息序列化,然后将其中所有可序列化的成员变量递归的方式序列化(成员变量是基本数据类型直接序列化,一般类类型递归序列化)。
写个例子测试一下:public class Human{
public Human(String a){}
}
public class Person extends Human implements Serializable{
public String xyz="lmn";
public String name;
public int age=55;
public int length=66;
public int width=77;
public Person(String name) {
super(name);
this.name=name;
}
}
private static void testSeriableEnum() throws IOException {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
// oos.writeObject(Gender.MAN);
oos.writeObject(new Person("abc"));
System.out.println(baos.toString());
}运行结果:
注意因为Human没有Serializable接口,所以序列化结果不包含Human的相关信息。
相关文章推荐
- 【JDK源码分析】02-对象反序列化ObjectInputStream
- jdk动态代理生成代理对象源码分析-4
- 【JDK源码分析】04-使用Externalizable实现自定义序列化
- Android SurfaceFlinger服务代理对象获取过程源码分析
- Android远程代理对象BpSurface的获取过程源码分析
- HashMap源码分析(基于JDK1.6)
- jdk 源码分析(17)java Semaphore 源码解析及与lock对比
- (转载)Java中HashMap底层实现原理(JDK1.8)源码分析
- Java Collections Framework之LinkedHashMap源码分析(基于JDK1.6)(??)
- Java Collections Framework之Arrays(method:sort(),binarySearch(),copyOf())部分源码分析(基于JDK1.6)
- JDK源码分析之String篇
- jdk源码--序列化
- ArrayList源码分析 JDK8
- java学习之旅63常用类_包装类_Integer_Number_JDK源码分析
- Java面试绕不开的问题: Java中HashMap底层实现原理(JDK1.8)源码分析
- ConcurrentHashMap源码分析(基于JDK1.8)
- 常用类第十二八课,包装类Integer,Number,JDK源码分析
- JDK源码分析之String、StringBuilder和StringBuffer
- JDK中String类的源码分析(一)
- MyBatis Mapper 接口如何通过JDK动态代理来包装SqlSession 源码分析