ObjectInputStream 和 ObjectOutputStream 都是和对象 Serializable 有关。
writeObject 的过程 原生数据类型的序列化 创建 ObjectOutputStream 的过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 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 ; } } void drain () throws IOException { if (pos == 0 ) { return ; } if (blkmode) { writeBlockHeader(pos); } out.write(buf, 0 , pos); pos = 0 ; }
BlockDataOutputStream 在什么时候会形成一个 data block.
在 drain 方法中,如果 当前是 块模式,则调用 writeBlockHeader 生成一个数据块头。
1 2 3 4 5 6 7 8 9 10 11 void drain () throws IOException { if (pos == 0 ) { return ; } if (blkmode) { writeBlockHeader(pos); } out.write(buf, 0 , pos); pos = 0 ; }
BlockDataOutputStream 的 blkmode 状态默认 false, 表示这个流是 关闭块模式。块模式表示的是 可以向这个流中写入数据,写入的数据默认存储在 buffer 中,当数据最终写入到 buffer 之前,会在这个前面加一个 BlockHeader。
ObjectOutputStream 内部有一个 BlockDataOutputStream 这个对象中拥有缓冲区,流的所有写入操作都先写入到这个对象的缓冲区中,
此时是写到,缓冲区的。 writeStreamHeader 写入流的 STREAM_MAGIC 和 STREAM_VERSION 共 4 个字节。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data" )); oos.writeInt(9999 ); oos.close(); STREAM_VERSION block_size ↓ ↓ ↓_________↓ ↓____↓ +----+----+----+----+----+----+----+----+----+----+ | AC | ED | 00 | 05 | 77 | 04 | 00 | 00 | 27 | 0f | +----+----+----+----+----+----+----+----+----+----+ ↑_________↑ ↑____↑ ↑___________________↑ ↑ ↑ ↑ STREAM_MAGIC TC_BLOCKDATA data 其中 data 存储的字节序是:大端。 并且 data 区域,并不维护,数据类型,数据数据的维护,由代码来维护,代码当然知道,写入的数据类型是什么。
对象类型的序列化 ObjectStreamClass
ObjectOutputStream.writeObject0
写入一个对象:
writeOrdinaryObject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 private void writeObject0 (Object obj, boolean unshared) throws IOException { Class cl = obj.getClass(); ObjectStreamClass desc; desc = ObjectStreamClass.lookup(cl, true ); writeOrdinaryObject(obj, desc, unshared); } 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(); } } } private void writeNonProxyDesc (ObjectStreamClass desc, boolean unshared) throws IOException { bout.writeByte(TC_CLASSDESC); handles.assign(unshared ? null : desc); if (protocol == PROTOCOL_VERSION_1) { desc.writeNonProxy(this ); } else { writeClassDescriptor(desc); } Class cl = desc.forClass(); bout.setBlockDataMode(true ); if (isCustomSubclass()) { ReflectUtil.checkPackageAccess(cl); } annotateClass(cl); bout.setBlockDataMode(false ); bout.writeByte(TC_ENDBLOCKDATA); writeClassDesc(desc.getSuperDesc(), false ); } 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()); } } } 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); } } }
同理,对于 readObject 方法的调用机制,也是如此,并且,如果 一个 Serializable 提供了 writeObject 方法,则其就应该提供 readObject 方法。这两个方法的签名是:
1 2 3 4 private void readObject (java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException ;private void writeObject (java.io.ObjectOutputStream stream) throws IOException
ObjectStreamClass 的构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 private ObjectStreamClass (final Class<?> cl) { serializable = Serializable.class.isAssignableFrom(cl); externalizable = Externalizable.class.isAssignableFrom(cl); Class<?> superCl = cl.getSuperclass(); superDesc = (superCl != null ) ? lookup(superCl, false ) : null ; if (serializable) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run () { fields = getSerialFields(cl); if (externalizable) { cons = getExternalizableConstructor(cl); } else { cons = getSerializableConstructor(cl); writeObjectMethod = getPrivateMethod(cl, "writeObject" , new Class<?>[] { ObjectOutputStream.class }, Void.TYPE); readObjectMethod = getPrivateMethod(cl, "readObject" , new Class<?>[] { ObjectInputStream.class }, Void.TYPE); readObjectNoDataMethod = getPrivateMethod( cl, "readObjectNoData" , null , Void.TYPE); hasWriteObjectData = (writeObjectMethod != null ); } writeReplaceMethod = getInheritableMethod( cl, "writeReplace" , null , Object.class); readResolveMethod = getInheritableMethod( cl, "readResolve" , null , Object.class); return null ; } }); } }
所以写入对象数据的过程,如下:
TC_OBJECT 表示一个对象
写入对象的类描述:例如类名,类中的字段名称,字段类型
写入对象数据,如果对象有 writeObject ,调用 writeObject 写入数据
如果对象没有 writeObject 方法,则调用 defaultWriteFields 将所有 non-static,non-transient 字段写入
其写入过程: 如果当前字段是原生数据类型,则直接写入,否则,进入递归调用,转到步骤 1 开始写入这个对象字段。直到当前对象的所有字段写完,返回
写 superClass 的数据,重复上面的步骤
直到 superClass 到根类 Object 类。