- 浏览: 759252 次
- 性别:
- 来自: 杭州
-
文章分类
最新评论
-
lgh1992314:
a offset: 26b offset: 24c offse ...
java jvm字节占用空间分析 -
ls0609:
语音实现在线听书http://blog.csdn.net/ls ...
Android 语音输入API使用 -
wangli61289:
http://viralpatel-net-tutorials ...
Android 语音输入API使用 -
zxjlwt:
学习了素人派http://surenpi.com
velocity宏加载顺序 -
tt5753:
谢啦........
Lucene的IndexWriter初始化时的LockObtainFailedException的解决方法
java的序列化机制原理分析
我们查看下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也类似。
相关推荐
让我们深入探讨一下Java序列化的机制和原理。 首先,Java序列化的主要目的是为了对象的持久化和在网络上的传输。为了使一个对象可以被序列化,该对象的类必须实现`java.io.Serializable`接口。这个接口没有任何方法...
首先,我们需要创建一个实现了`Serializable`接口的类`TestSerial`,这样Java序列化机制才能处理这个类的对象。 接下来,我们编写代码将对象序列化并输出为字节流,存储在一个临时文件`temp.out`中。 ```java ...
Java序列化是Java平台中的一种标准机制,它允许将对象的状态转换为字节流,以便存储、传输或恢复。在Java中,一个类如果要实现序列化,需要实现`Serializable`接口,这是一个标记接口,不包含任何方法。下面我们将...
在给定的链接"Java序列化机制(2)- serialVersionUID 实验"中,博主通过一个实验详细解释了`serialVersionUID`的作用和重要性。实验可能包括以下步骤: 1. 创建一个实现`Serializable`接口的简单类,并运行序列化...
### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化是什么? 序列化是指将程序中的对象转换为字节流的过程,从而方便存储或传输这些对象。通常,序列化用于将对象的状态(即其实例变量的值,而非...
序列化ID,即`serialVersionUID`,是Java序列化机制中一个关键的概念。它是一个类的唯一标识符,用于在序列化和反序列化过程中确定类的版本一致性。如果序列化对象和反序列化对象的`serialVersionUID`不匹配,将会抛...
Java序列化是将Java对象转换为字节流的过程,以便可以在网络上传输或存储在磁盘上。这使得数据能够跨不同的系统平台进行传输和持久化。Protocol Buffers(protobuf)是Google推出的一种高效、跨平台的数据序列化协议...
**FST:快速Java序列化的替代方案** 在Java开发中,序列化是一个常见的需求,它允许将对象的状态转换为字节流,以便于存储或网络传输。标准的Java序列化虽然方便,但在处理大量数据时,性能往往成为瓶颈。这时,FST...
Java序列化机制是Java平台提供的一种标准方法,用于将对象的状态转换为字节序列,以便在网络中传输或存储在磁盘、数据库等持久化介质中。这一机制在分布式环境、远程通信、持久化存储和数据交换等多个场景下具有广泛...
以下是关于Java序列化机制和原理的详细解释: 1. **序列化接口**: Java中的序列化是通过实现`Serializable`接口来实现的。这个接口没有任何方法,它的存在仅仅是为了标记一个类可以被序列化。如以下示例所示: `...
Java对象序列化是Java平台提供的一种机制,允许将对象的状态转换为字节流,以便存储在磁盘上、通过网络传输或在不同时间点恢复。这个过程涉及到将一个复杂的Java对象模型转换为简单的二进制表示,使得数据可以在不同...
此外,还将深入讨论如何精准控制序列化机制,帮助读者在实际编程中正确运用Java序列化技术,避免常见误区,并掌握高效利用该技术的方法。 **关键词:** 序列化(Serialize)、反序列化(DeSerialize)、类加载...
1. **Java序列化机制**:Java对象序列化是通过实现`Serializable`接口来标记一个类可被序列化。`ObjectOutputStream`用于将对象写入流,`ObjectInputStream`用于从流中读取并反序列化对象。 2. **易受攻击的库**:...
接下来,我们讨论Parcelable,这是Android特有的序列化机制,主要用于内存中的对象传输,例如在Activity之间传递数据或者保存到Bundle中。相比于Serializable,Parcelable提供了更高的性能和更低的内存消耗。实现...
3. **Protobuf**: Google的协议缓冲区,提供高效的序列化机制,适用于网络通信和数据存储,具有较小的体积和更快的速度。 四、反序列化安全问题 1. **代码执行漏洞**: 不安全的反序列化可能导致远程代码执行。攻击...
标签中的“源码”提示我们,了解这些序列化机制的内部工作原理,查看源代码可以帮助我们更深入地理解其优化点和可能的改进空间。“工具”则意味着除了理论知识,还有实际可用的库和工具可以帮助我们在项目中实施这些...
Java序列化不仅仅是对数据的简单编码,更重要的是它涉及到对象的生命周期和状态的保存。 要实现对象的序列化,Java对象必须实现`Serializable`接口。这是一个特殊的标识接口,不包含任何方法,它的作用仅仅是标记一...
Java序列化是将Java对象转换为字节流的过程,以便可以在磁盘、数据库或网络上进行存储和传输。这个过程允许我们保存对象的状态,并在需要时恢复它,这对于持久化数据、跨网络通信或者实现RMI(远程方法调用)等场景...
管理系统源码.zip、README.txt 在本项目中,“学生管理系统(序列化和反序列化)”是一个基于Java或类似编程语言实现的系统,其核心功能是...在开发类似的系统时,理解并掌握序列化和反序列化的核心原理是非常重要的。