- 浏览: 980183 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
Java Socket编程实例:http://donald-draper.iteye.com/blog/2356695
java Socket读写缓存区Writer和Reader:http://donald-draper.iteye.com/blog/2356885
Java NIO ByteBuffer详解:http://donald-draper.iteye.com/blog/2357084
Java序列化与反序列化实例分析:http://donald-draper.iteye.com/blog/2357515
在上面一篇Java序列化与反序列化教程,我们通过实例,分析了Java序列化与反序列化,今天我们来更深入的去看一下ObjectOutputStream和ObjectInputStream是如何序列化与反序列化对象和原始类型的;
1.序列化
序列化的关键在这几句
我们一句一句的分析,先看构造ObjectOutputStream
先看构造
再来一下BlockDataOutputStream,BlockDataOutputStream为ObjectOutputStream的静态内部类
再看DataOutputStream
//DataOutputStream(DataOutput),主要用于写原始类型数据,int,float,String,double等
从上面可以看出,ObjectOutputStream的构造,主要是构造对象,对象输出流BlockDataOutputStream,BlockDataOutputStream主要是写序列化的流数据,BlockDataOutputStream中有一个存放序列化数据
的缓存区,头部数据缓冲区,原始类型数据缓冲区,其中关联一个原始类型输出流DataOutputStream,(DataOutput)主要用于写原始类型数据,int,float,String,double等;同时写流版本号和流魔数。
现在来看一下如何对象序列化:
//序列化对象
//如果是Class对象,则调用writeClass
//序列化对象类型
来看这一句:
先看一下ObjectStreamClass对象
回到这一句:
回到
//序列化对象类型
的这一句
//写流对象
//ObjectStreamClass
//ObjectStreamField
到这类写流对象描述完毕,主要写类名,序列版本号,类型,属性个数,属性描述;
回到写对象属性值;
//序列化兑现跟这个是关键
//写对象属性值
分两步
//如果是Externalizable接口则,调用writeExternalData
//如果是Serializable接口则,调用writeSerialData
先看
//如果是Serializable接口则,调用writeSerialData
//否则,写Field
来看一下这个:
//通过反射,获取属性值
//ObjectStreamClass
//FieldReflector
再看
//如果是Externalizable接口则,调用writeExternalData
从上面当对象父接口是Serializable,如果Serializable实现了WriteObject方法,则直接调用WriteObject序列化属性值,否则,通过反射获取对象属性的值,写到缓存中,如果对象父接口Externalizable,则直接调用对象writeExternal方法序列化对象。
再看看一下原始类型的序列化
//ObjectOutputStream
//BlockDataOutputStream
再来看写UTF字符串
//ObjectOutputStream
//BlockDataOutputStream
//刷新缓存
//ObjectOutputStream
//BlockDataOutputStream
总结:
ObjectOutputStream的构造,主要是构造对象,对象输出流BlockDataOutputStream,BlockDataOutputStream主要是写序列化的流数据,BlockDataOutputStream中有一个存放序列化数据
的缓存区,头部数据缓冲区,原始类型数据缓冲区,其中关联一个原始类型输出流DataOutputStream,(DataOutput)主要用于写原始类型数据,int,float,String,double等;同时写流版本号和流魔数。然后,写类流对象描述,主要写类名,序列版本号,类型,属性个数,属性描述;然后写对象属性值,当对象父接口是Serializable,如果Serializable实现了WriteObject方法,则直接调用WriteObject序列化属性值,否则,通过反射获取对象属性的值,写到缓存中,如果对象父接口Externalizable,则直接调用对象writeExternal方法序列化对象。
2.反序列化
看了序列化的过程,我们应该可以反推,反序列,这里不细讲,直接主要类的构造,属性
// BlockDataInputStream
//PeekInputStream
来看一个readint
//ObjectInputStream
//BlockDataInputStream
附:
//DataOutputStream
java Socket读写缓存区Writer和Reader:http://donald-draper.iteye.com/blog/2356885
Java NIO ByteBuffer详解:http://donald-draper.iteye.com/blog/2357084
Java序列化与反序列化实例分析:http://donald-draper.iteye.com/blog/2357515
在上面一篇Java序列化与反序列化教程,我们通过实例,分析了Java序列化与反序列化,今天我们来更深入的去看一下ObjectOutputStream和ObjectInputStream是如何序列化与反序列化对象和原始类型的;
1.序列化
ObjectOutputStream objectOutputStream = null; try { objectOutputStream = new ObjectOutputStream(outFile); } catch (IOException e) { e.printStackTrace(); } PersonX person = new PersonX("donald", 27, "man"); try { objectOutputStream.writeObject(person); objectOutputStream.writeInt(4); objectOutputStream.writeUTF("it is a man"); objectOutputStream.close(); } catch (IOException e) { e.printStackTrace(); }
序列化的关键在这几句
objectOutputStream = new ObjectOutputStream(outFile); objectOutputStream.writeObject(person); objectOutputStream.writeInt(4); objectOutputStream.writeUTF("it is a man");
我们一句一句的分析,先看构造ObjectOutputStream
public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants { /** filter stream for handling block data conversion */ private final BlockDataOutputStream bout;//对象数据输出流 /** stream protocol version */ private int protocol = PROTOCOL_VERSION_2; ** buffer for writing primitive field values */ private byte[] primVals; /** if true, invoke writeObjectOverride() instead of writeObject() */ private final boolean enableOverride; }
先看构造
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; } } /** * The writeStreamHeader method is provided so subclasses can append or * prepend their own header to the stream. It writes the magic number and * version to the stream. *写流版本号和流魔数 * @throws IOException if I/O errors occur while writing to the underlying * stream */ protected void writeStreamHeader() throws IOException { bout.writeShort(STREAM_MAGIC); bout.writeShort(STREAM_VERSION); }
再来一下BlockDataOutputStream,BlockDataOutputStream为ObjectOutputStream的静态内部类
private static class BlockDataOutputStream extends OutputStream implements DataOutput { /** maximum data block length */ private static final int MAX_BLOCK_SIZE = 1024; /** maximum data block header length */ private static final int MAX_HEADER_SIZE = 5; /** (tunable) length of char buffer (for writing strings) */ private static final int CHAR_BUF_SIZE = 256; /** buffer for writing general/block data ,存放对象序列化数据*/ private final byte[] buf = new byte[MAX_BLOCK_SIZE]; /** buffer for writing block data headers,存放数据头部 */ private final byte[] hbuf = new byte[MAX_HEADER_SIZE]; /** char buffer for fast string writes ,这个用于直接写原始类型*/ private final char[] cbuf = new char[CHAR_BUF_SIZE]; /** block data mode */ private boolean blkmode = false; /** current offset into buf */ private int pos = 0; /** underlying output stream */ private final OutputStream out; /** loopback stream (for data writes that span data blocks),写原始数据的输出流 */ private final DataOutputStream dout; /** * Creates new BlockDataOutputStream on top of given underlying stream. * Block data mode is turned off by default. */ BlockDataOutputStream(OutputStream out) { this.out = out; dout = new DataOutputStream(this); }
再看DataOutputStream
//DataOutputStream(DataOutput),主要用于写原始类型数据,int,float,String,double等
public class DataOutputStream extends FilterOutputStream implements DataOutput { /** * The number of bytes written to the data output stream so far. * If this counter overflows, it will be wrapped to Integer.MAX_VALUE. */ protected int written; /** * bytearr is initialized on demand by writeUTF */ private byte[] bytearr = null; /** * Creates a new data output stream to write data to the specified * underlying output stream. The counter <code>written</code> is * set to zero. * * @param out the underlying output stream, to be saved for later * use. * @see java.io.FilterOutputStream#out */ public DataOutputStream(OutputStream out) { super(out); }
从上面可以看出,ObjectOutputStream的构造,主要是构造对象,对象输出流BlockDataOutputStream,BlockDataOutputStream主要是写序列化的流数据,BlockDataOutputStream中有一个存放序列化数据
的缓存区,头部数据缓冲区,原始类型数据缓冲区,其中关联一个原始类型输出流DataOutputStream,(DataOutput)主要用于写原始类型数据,int,float,String,double等;同时写流版本号和流魔数。
现在来看一下如何对象序列化:
public final void writeObject(Object obj) throws IOException { ... try { //委托给writeObject0 writeObject0(obj, false); } ... }
//序列化对象
private void writeObject0(Object obj, boolean unshared) throws IOException { 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) { //如果是Class对象,则调用writeClass writeClass((Class) obj, unshared); return; } else if (obj instanceof ObjectStreamClass) { //如果是对象序列化流类型writeClassDesc writeClassDesc((ObjectStreamClass) obj, unshared); return; } ... // remaining cases if (obj instanceof String) { //如果对象为String直接调用writeString writeString((String) obj, unshared); } else if (cl.isArray()) { //Array writeArray(obj, desc, unshared); } else if (obj instanceof Enum) { //枚举 writeEnum((Enum) obj, desc, unshared); } else if (obj instanceof Serializable) { //序列化兑现跟这个是关键 writeOrdinaryObject(obj, desc, unshared); } .... }
//如果是Class对象,则调用writeClass
writeClass((Class) obj, unshared);
//序列化对象类型
private void writeClass(Class cl, boolean unshared) throws IOException { bout.writeByte(TC_CLASS); //写流对象 writeClassDesc(ObjectStreamClass.lookup(cl, true), false); handles.assign(unshared ? null : cl); }
来看这一句:
ObjectStreamClass.lookup(cl, true)
先看一下ObjectStreamClass对象
public class ObjectStreamClass implements Serializable { /** serialPersistentFields value indicating no serializable fields */ //序列化对象属相描述 public static final ObjectStreamField[] NO_FIELDS = new ObjectStreamField[0]; /** reflection factory for obtaining serialization constructors */ private static final ReflectionFactory reflFactory = AccessController.doPrivileged( new ReflectionFactory.GetReflectionFactoryAction()); private static class Caches { /** cache mapping local classes -> descriptors,类描述缓存 */ static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs = new ConcurrentHashMap<>(); /** cache mapping field group/local desc pairs -> field reflectors */ static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors = new ConcurrentHashMap<>(); /** queue for WeakReferences to local classes */ private static final ReferenceQueue<Class<?>> localDescsQueue = new ReferenceQueue<>(); /** queue for WeakReferences to field reflectors keys */ private static final ReferenceQueue<Class<?>> reflectorsQueue = new ReferenceQueue<>(); } /** class associated with this descriptor (if any) */ private Class<?> cl; /** name of class represented by this descriptor */ private String name; /** serialVersionUID of represented class (null if not computed yet) */ private volatile Long suid; /** true if represents dynamic proxy class */ private boolean isProxy; /** true if represents enum type */ private boolean isEnum; /** true if represented class implements Serializable */ private boolean serializable; /** true if represented class implements Externalizable */ private boolean externalizable; /** true if desc has data written by class-defined writeObject method */ private boolean hasWriteObjectData; /** exception (if any) thrown while attempting to resolve class */ private ClassNotFoundException resolveEx; /** exception (if any) to throw if non-enum deserialization attempted */ private ExceptionInfo deserializeEx; /** exception (if any) to throw if non-enum serialization attempted */ private ExceptionInfo serializeEx; /** exception (if any) to throw if default serialization attempted */ private ExceptionInfo defaultSerializeEx; /** serializable fields */ private ObjectStreamField[] fields; /** aggregate marshalled size of primitive fields */ private int primDataSize; /** number of non-primitive fields */ private int numObjFields; /** reflector for setting/getting serializable field values */ private FieldReflector fieldRefl; /** data layout of serialized objects described by this class desc */ private volatile ClassDataSlot[] dataLayout; /** serialization-appropriate constructor, or null if none */ private Constructor cons; /** class-defined writeObject method, or null if none */ private Method writeObjectMethod; /** class-defined readObject method, or null if none */ private Method readObjectMethod; /** class-defined readObjectNoData method, or null if none */ private Method readObjectNoDataMethod; /** class-defined writeReplace method, or null if none */ private Method writeReplaceMethod; /** class-defined readResolve method, or null if none */ private Method readResolveMethod; }
回到这一句:
ObjectStreamClass.lookup(cl, true) static ObjectStreamClass lookup(Class<?> cl, boolean all) { if (!(all || Serializable.class.isAssignableFrom(cl))) { return null; } //从缓存中获取对象流描述 processQueue(Caches.localDescsQueue, Caches.localDescs); WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue); Reference<?> ref = Caches.localDescs.get(key); ... 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)); } 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 void writeClass(Class cl, boolean unshared) throws IOException { bout.writeByte(TC_CLASS); //写流对象 writeClassDesc(ObjectStreamClass.lookup(cl, true), false); handles.assign(unshared ? null : cl); }
的这一句
//写流对象
writeClassDesc(ObjectStreamClass.lookup(cl, true), 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()) { writeProxyDesc(desc, unshared); } else { //写非代理对象描述 writeNonProxyDesc(desc, unshared); } }
//写非代理对象描述 /* 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); handles.assign(unshared ? null : desc); if (protocol == PROTOCOL_VERSION_1) { // do not invoke class descriptor write hook with old protocol desc.writeNonProxy(this); } else { //从前面可以看出,协议版本为PROTOCOL_VERSION_2 writeClassDescriptor(desc); } Class cl = desc.forClass(); bout.setBlockDataMode(true); annotateClass(cl); bout.setBlockDataMode(false); bout.writeByte(TC_ENDBLOCKDATA); //写父类的类描述 writeClassDesc(desc.getSuperDesc(), false); } protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException { //委托给writeNonProxy desc.writeNonProxy(this); }
//ObjectStreamClass
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()); } } }
//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 unshared; /** corresponding reflective field object, if any */ private final Field field; /** offset of field value in enclosing field group */ private int offset = 0; }
到这类写流对象描述完毕,主要写类名,序列版本号,类型,属性个数,属性描述;
回到写对象属性值;
//序列化兑现跟这个是关键
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()) { //如果是Externalizable接口则,调用writeExternalData writeExternalData((Externalizable) obj); } else { //如果是Serializable接口则,调用writeSerialData writeSerialData(obj, desc); } } finally { if (extendedDebugInfo) { debugInfoStack.pop(); } } }
分两步
//如果是Externalizable接口则,调用writeExternalData
writeExternalData((Externalizable) obj);
//如果是Serializable接口则,调用writeSerialData
writeSerialData(obj, desc);
先看
//如果是Serializable接口则,调用writeSerialData
writeSerialData(obj, desc);
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); //如果对象实现了WriteObject方法,则调用WriteObject方法 slotDesc.invokeWriteObject(obj, this); bout.setBlockDataMode(false); bout.writeByte(TC_ENDBLOCKDATA); } finally { curContext.setUsed(); curContext = oldContext; if (extendedDebugInfo) { debugInfoStack.pop(); } } curPut = oldPut; } else { //否则,写Field defaultWriteFields(obj, slotDesc); } } }
//否则,写Field
defaultWriteFields(obj, slotDesc);
private void defaultWriteFields(Object obj, ObjectStreamClass desc) throws IOException { // REMIND: perform conservative isInstance check here? 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(); } } } }
来看一下这个:
//通过反射,获取属性值
desc.getObjFieldValues(obj, objVals);
//ObjectStreamClass
/** * Fetches the serializable object field values of object obj and stores * them in array vals starting at offset 0. It is the responsibility of * the caller to ensure that obj is of the proper type if non-null. */ void getObjFieldValues(Object obj, Object[] vals) { //** reflector for setting/getting serializable field values */ //private FieldReflector fieldRefl; //属性对应的set&get方法反射器 fieldRefl.getObjFieldValues(obj, vals); } /** * Fetches the serializable object field values of object obj and * stores them in array vals starting at offset 0. The caller is * responsible for ensuring that obj is of the proper type. */ void getObjFieldValues(Object obj, Object[] vals) { if (obj == null) { throw new NullPointerException(); } /* assuming checkDefaultSerialize() has been called on the class * descriptor this FieldReflector was obtained from, no field keys * in array should be equal to Unsafe.INVALID_FIELD_OFFSET. */ for (int i = numPrimFields; i < fields.length; i++) { switch (typeCodes[i]) { case 'L': case '[': vals[offsets[i]] = unsafe.getObject(obj, readKeys[i]); break; default: throw new InternalError(); } } }
//FieldReflector
private static class FieldReflector { /** handle for performing unsafe operations */ private static final Unsafe unsafe = Unsafe.getUnsafe(); /** fields to operate on */ private final ObjectStreamField[] fields; /** number of primitive fields */ private final int numPrimFields; /** unsafe field keys for reading fields - may contain dupes */ private final long[] readKeys; /** unsafe fields keys for writing fields - no dupes */ private final long[] writeKeys; /** field data offsets */ private final int[] offsets; /** field type codes */ private final char[] typeCodes; /** field types */ private final Class<?>[] types; }
再看
//如果是Externalizable接口则,调用writeExternalData
writeExternalData((Externalizable) obj);
private void writeExternalData(Externalizable obj) throws IOException { PutFieldImpl oldPut = curPut; curPut = null; if (extendedDebugInfo) { debugInfoStack.push("writeExternal data"); } SerialCallbackContext oldContext = curContext; try { curContext = null; if (protocol == PROTOCOL_VERSION_1) { obj.writeExternal(this); } else { bout.setBlockDataMode(true); //直接调用obj的writeExternal方法 obj.writeExternal(this); bout.setBlockDataMode(false); bout.writeByte(TC_ENDBLOCKDATA); } } finally { curContext = oldContext; if (extendedDebugInfo) { debugInfoStack.pop(); } } curPut = oldPut; }
从上面当对象父接口是Serializable,如果Serializable实现了WriteObject方法,则直接调用WriteObject序列化属性值,否则,通过反射获取对象属性的值,写到缓存中,如果对象父接口Externalizable,则直接调用对象writeExternal方法序列化对象。
再看看一下原始类型的序列化
//ObjectOutputStream
public void writeInt(int val) throws IOException { //直接委托给bout bout.writeInt(val); }
//BlockDataOutputStream
public void writeInt(int v) throws IOException { if (pos + 4 <= MAX_BLOCK_SIZE) { //这个前面文章已说,这一不在说了 Bits.putInt(buf, pos, v); pos += 4; } else { dout.writeInt(v); } }
再来看写UTF字符串
//ObjectOutputStream
public void writeUTF(String str) throws IOException { bout.writeUTF(str); }
//BlockDataOutputStream
public void writeUTF(String s) throws IOException { writeUTF(s, getUTFLength(s)); } 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); } } /** * Writes the "body" (i.e., the UTF representation minus the 2-byte or * 8-byte length header) of the UTF encoding for the given string. */ private void writeUTFBody(String s) throws IOException { int limit = MAX_BLOCK_SIZE - 3; int len = s.length(); for (int off = 0; off < len; ) { int csize = Math.min(len - off, CHAR_BUF_SIZE); s.getChars(off, off + csize, cbuf, 0); for (int cpos = 0; cpos < csize; cpos++) { char c = cbuf[cpos]; if (pos <= limit) { if (c <= 0x007F && c != 0) { buf[pos++] = (byte) c; } else if (c > 0x07FF) { buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F)); buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F)); buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F)); pos += 3; } else { buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F)); buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F)); pos += 2; } } else { // write one byte at a time to normalize block if (c <= 0x007F && c != 0) { write(c); } else if (c > 0x07FF) { write(0xE0 | ((c >> 12) & 0x0F)); write(0x80 | ((c >> 6) & 0x3F)); write(0x80 | ((c >> 0) & 0x3F)); } else { write(0xC0 | ((c >> 6) & 0x1F)); write(0x80 | ((c >> 0) & 0x3F)); } } } off += csize; } }
//刷新缓存
//ObjectOutputStream
public void flush() throws IOException { bout.flush(); }
//BlockDataOutputStream
public void flush() throws IOException { drain(); out.flush(); }
总结:
ObjectOutputStream的构造,主要是构造对象,对象输出流BlockDataOutputStream,BlockDataOutputStream主要是写序列化的流数据,BlockDataOutputStream中有一个存放序列化数据
的缓存区,头部数据缓冲区,原始类型数据缓冲区,其中关联一个原始类型输出流DataOutputStream,(DataOutput)主要用于写原始类型数据,int,float,String,double等;同时写流版本号和流魔数。然后,写类流对象描述,主要写类名,序列版本号,类型,属性个数,属性描述;然后写对象属性值,当对象父接口是Serializable,如果Serializable实现了WriteObject方法,则直接调用WriteObject序列化属性值,否则,通过反射获取对象属性的值,写到缓存中,如果对象父接口Externalizable,则直接调用对象writeExternal方法序列化对象。
2.反序列化
ObjectInputStream objectInputStream = null; try { objectInputStream = new ObjectInputStream(inFile); } catch (IOException e) { e.printStackTrace(); } PersonX getPerson = null; try { getPerson = (PersonX) objectInputStream.readObject(); int int0 = objectInputStream.readInt(); System.out.println("=======read int after read object persion:"+int0); String str = objectInputStream.readUTF(); System.out.println("=======read UTF after read object persion and int:"+str); objectInputStream.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
看了序列化的过程,我们应该可以反推,反序列,这里不细讲,直接主要类的构造,属性
public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants { /** filter stream for handling block data conversion */ private final BlockDataInputStream bin; /** validation callback list */ private final ValidationList vlist; /** recursion depth */ private int depth; /** whether stream is closed */ private boolean closed; /** wire handle -> obj/exception map */ private final HandleTable handles; /** scratch field for passing handle values up/down call stack */ private int passHandle = NULL_HANDLE; /** flag set when at end of field value block with no TC_ENDBLOCKDATA */ private boolean defaultDataEnd = false; /** buffer for reading primitive field values */ private byte[] primVals; /** if true, invoke readObjectOverride() instead of readObject() */ private final boolean enableOverride; /** if true, invoke resolveObject() */ private boolean enableResolve; /** * Context during upcalls to class-defined readObject methods; holds * object currently being deserialized and descriptor for current class. * Null when not during readObject upcall. */ private SerialCallbackContext curContext; }
// BlockDataInputStream
private class BlockDataInputStream extends InputStream implements DataInput { /** maximum data block length */ private static final int MAX_BLOCK_SIZE = 1024; /** maximum data block header length */ private static final int MAX_HEADER_SIZE = 5; /** (tunable) length of char buffer (for reading strings) */ private static final int CHAR_BUF_SIZE = 256; /** readBlockHeader() return value indicating header read may block */ private static final int HEADER_BLOCKED = -2; /** buffer for reading general/block data */ private final byte[] buf = new byte[MAX_BLOCK_SIZE]; /** buffer for reading block data headers */ private final byte[] hbuf = new byte[MAX_HEADER_SIZE]; /** char buffer for fast string reads */ private final char[] cbuf = new char[CHAR_BUF_SIZE]; /** block data mode */ private boolean blkmode = false; // block data state fields; values meaningful only when blkmode true /** current offset into buf */ private int pos = 0; /** end offset of valid data in buf, or -1 if no more block data */ private int end = -1; /** number of bytes in current block yet to be read from stream */ private int unread = 0; /** underlying stream (wrapped in peekable filter stream) */ private final PeekInputStream in; /** loopback stream (for data reads that span data blocks) */ private final DataInputStream din; /** * Creates new BlockDataInputStream on top of given underlying stream. * Block data mode is turned off by default. */ BlockDataInputStream(InputStream in) { this.in = new PeekInputStream(in); din = new DataInputStream(this); } }
//PeekInputStream
/** * Input stream supporting single-byte peek operations. */ private static class PeekInputStream extends InputStream { /** underlying stream */ private final InputStream in; /** peeked byte */ private int peekb = -1; /** * Creates new PeekInputStream on top of given underlying stream. */ PeekInputStream(InputStream in) { this.in = in; } /** * Peeks at next byte value in stream. Similar to read(), except * that it does not consume the read value. */ int peek() throws IOException { return (peekb >= 0) ? peekb : (peekb = in.read()); } public int read() throws IOException { if (peekb >= 0) { int v = peekb; peekb = -1; return v; } else { return in.read(); } } public int read(byte[] b, int off, int len) throws IOException { if (len == 0) { return 0; } else if (peekb < 0) { return in.read(b, off, len); } else { b[off++] = (byte) peekb; len--; peekb = -1; int n = in.read(b, off, len); return (n >= 0) ? (n + 1) : 1; } } void readFully(byte[] b, int off, int len) throws IOException { int n = 0; while (n < len) { int count = read(b, off + n, len - n); if (count < 0) { throw new EOFException(); } n += count; } } public long skip(long n) throws IOException { if (n <= 0) { return 0; } int skipped = 0; if (peekb >= 0) { peekb = -1; skipped++; n--; } return skipped + skip(n); } public int available() throws IOException { return in.available() + ((peekb >= 0) ? 1 : 0); } public void close() throws IOException { in.close(); } }
来看一个readint
//ObjectInputStream
public int readInt() throws IOException { return bin.readInt(); }
//BlockDataInputStream
public int readInt() throws IOException { if (!blkmode) { pos = 0; in.readFully(buf, 0, 4); } else if (end - pos < 4) { return din.readInt(); } int v = Bits.getInt(buf, pos); pos += 4; return v; }
附:
//DataOutputStream
public class DataOutputStream extends FilterOutputStream implements DataOutput { /** * The number of bytes written to the data output stream so far. * If this counter overflows, it will be wrapped to Integer.MAX_VALUE. */ protected int written; /** * bytearr is initialized on demand by writeUTF */ private byte[] bytearr = null; /** * Creates a new data output stream to write data to the specified * underlying output stream. The counter <code>written</code> is * set to zero. * * @param out the underlying output stream, to be saved for later * use. * @see java.io.FilterOutputStream#out */ public DataOutputStream(OutputStream out) { super(out); } }
public class DataInputStream extends FilterInputStream implements DataInput { /** * Creates a DataInputStream that uses the specified * underlying InputStream. * * @param in the specified input stream */ public DataInputStream(InputStream in) { super(in); } /** * working arrays initialized on demand by readUTF */ private byte bytearr[] = new byte[80]; private char chararr[] = new char[80]; }
发表评论
-
文件通道解析二(文件锁,关闭通道)
2017-05-16 23:17 1065文件通道解析一(读写操作,通道数据传输等):http://do ... -
文件通道解析一(读写操作,通道数据传输等)
2017-05-16 10:04 1164Reference定义(PhantomRefere ... -
文件通道创建方式综述
2017-05-15 17:39 1066Reference定义(PhantomReference,Cl ... -
文件读写方式简单综述后续(文件,流构造)
2017-05-14 23:04 1480Java Socket通信实例:http://donald-d ... -
文件读写方式简单综述
2017-05-14 11:13 1135Java Socket通信实例:http://donald-d ... -
FileChanne定义
2017-05-12 23:28 936文件读写方式简单综述:http://donald-draper ... -
SeekableByteChannel接口定义
2017-05-11 08:43 1235ByteChannel,分散聚集通道接口的定义(SocketC ... -
FileChannel示例
2017-05-11 08:37 992前面我们看过socket通道,datagram通道,以管道Pi ... -
PipeImpl解析
2017-05-11 08:41 932ServerSocketChannel定义:http://do ... -
Pipe定义
2017-05-10 09:07 904Channel接口定义:http://donald-drape ... -
NIO-Pipe示例
2017-05-10 08:47 905PipeImpl解析:http://donald-draper ... -
DatagramChannelImpl 解析四(地址绑定,关闭通道等)
2017-05-10 08:27 776DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析三(多播)
2017-05-10 08:20 1893DatagramChannelImpl 解析一(初始化):ht ... -
NIO-UDP实例
2017-05-09 12:32 1585DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析二(报文发送与接收)
2017-05-09 09:03 1405DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析一(初始化)
2017-05-08 21:52 1407Channel接口定义:http://donald-drape ... -
MembershipKeyImpl 简介
2017-05-08 09:11 923MembershipKey定义:http://donald-d ... -
DatagramChannel定义
2017-05-07 23:13 1228Channel接口定义:http://donald-drape ... -
MulticastChanne接口定义
2017-05-07 13:45 1136NetworkChannel接口定义:ht ... -
MembershipKey定义
2017-05-06 16:20 916package java.nio.channels; i ...
相关推荐
### Java序列化与反序列化详解 #### 一、Java序列化概述 Java序列化(Serialization)是一项重要的功能,它可以将对象的状态转化为一系列字节,从而实现对象的持久化存储或在网络上传输。序列化机制使得Java对象...
### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化的概念 序列化是指将程序中的对象转换为一系列字节流的过程,主要用于保存对象的状态或在网络之间传输对象。序列化的主要目的是为了能够持久化...
### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化是什么? 序列化是指将程序中的对象转换为字节流的过程,从而方便存储或传输这些对象。通常,序列化用于将对象的状态(即其实例变量的值,而非...
java 序列化与反序列化的实例详解 Java 序列化与反序列化是 Java 编程语言中的一种机制,允许将 Java 对象转换为字节序列,并将其反序列化回 Java 对象。序列化是指将 Java 对象转换为字节序列的过程,而反序列化是...
Java序列化是Java平台中的一种核心机制,它允许对象的状态被转换成字节流,以便存储到磁盘、数据库,或者在网络中进行传输。这对于实现持久化、远程方法调用(RMI)以及Enterprise JavaBeans(EJB)等高级功能至关...
本文将深入探讨JSON的序列化与反序列化过程,以及如何使用Gson、FastJson和Jackson这三种流行的Java库来实现这一功能。 一、什么是JSON序列化与反序列化? 1. JSON序列化:序列化是指将Java对象转换为JSON字符串的...
### Java序列化与反序列化的深入解析 #### 序列化的功能与意义 序列化是Java编程语言中的一项核心功能,其主要目的是将对象的状态转换为可以存储或传输的格式,便于持久化保存或网络传输。序列化并不涉及对象的...
### Java序列化原理与算法详解 #### 序言 在现代软件开发中,尤其是在网络通信和数据持久化领域,对象的序列化与反序列化扮演着至关重要的角色。Java作为一种广泛应用的编程语言,提供了强大的内置支持来实现序列化...
### 序列化与反序列化详解 #### 一、概念理解 序列化与反序列化是编程领域中非常重要的技术之一,它们主要用于将对象的状态转换为可以存储或传输的形式,以便于对象状态的持久化或者跨进程传输。具体而言: - **...
本文将深入探讨Java中的对象序列化与反序列化的概念、原理、实现方法以及相关的注意事项。 **一、对象序列化的概念和作用** 对象序列化是将一个Java对象转换成字节流的过程,这个字节流可以存储在磁盘上,也可以在...
Java 序列化和反序列化实例详解 Java 序列化和反序列化是 Java 语言中两个重要的概念,它们在分布式应用中扮演着至关重要的角色。序列化是指将对象转换为字节流的过程,而反序列化则是指将字节流恢复为对象的过程。...
5. [Java 序列化与反序列化详解](https://www.cnblogs.com/kingbridge/articles/16717030.html) 通过以上分析可以看出,Nacos JRaft Hessian 反序列化 RCE 分析是一个复杂的技术过程,涉及到多个技术细节和安全考虑...
### Java对象序列化标准知识点详解 #### 一、系统架构概览 **1.1 概览** Java 对象序列化是一种将Java对象的...以上内容涵盖了Java序列化标准的关键知识点,深入了解这些概念有助于更好地理解和应用Java序列化技术。
这使得Java的反序列化更加灵活,但也带来了安全风险,因为恶意用户可以通过构造特殊的序列化数据来触发意想不到的行为,比如执行任意代码。 PHP的序列化和反序列化则相对封闭,开发者无法直接修改序列化数据流,...
### C#对象序列化与反序列化 #### 1. 对象序列化的介绍 ##### (1).NET支持对象序列化的几种方式 .NET框架提供了多种序列化机制,它们各自有不同的应用场景和特点。 - **二进制序列化**: - **定义**:二进制...
这就需要Java序列化与反序列化了! 序列化的好处有两个:一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里);二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。总...
### Java中的序列化与反序列化详解 #### 一、概念理解 在Java中,序列化(Serialization)指的是将对象的状态转化为字节流的过程,这一过程通常用于存储对象或者在网络中传输对象。相反地,反序列化...
### Java反序列化实战知识点详解 #### 一、反序列化概述 - **定义**:在计算机科学领域,反序列化是指将字节流或文本流等数据转换回其原始对象结构的过程。这一过程通常与序列化相对应,序列化是将对象的状态转化...
Java 序列化与反序列化(Serialization)知识点总结 Java 序列化与反序列化是 Java 语言中的一种机制,用于将对象的状态信息转化为可以存储或者传输的形式的过程。序列化(Serialization)是将对象的状态信息转化为...
**序列化与反序列化** 序列化是将对象转换为可存储或可传输的形式的过程,而反序列化则是将这种形式的数据恢复为原来的对象。MsgPack库通过高效地编码和解码数据结构,实现了快速的序列化和反序列化。这在处理大量...