- 浏览: 740514 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
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的解决方法
下面我们来分析下序列化后的字节流内容:
先写一段测试代码:
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class SeriableTest { public static void main(String[] args) throws FileNotFoundException, IOException { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("e:\\log\\aa.txt"))); out.writeInt(123); out.writeUTF("str12345"); out.close(); // ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("e:\\log\\aa.txt"))); // int a = in.readInt(); // String test = in.readUTF(); // System.out.println(a); // System.out.println(test); // in.close(); } }
我们查看文件的内容:
其中0xACED是序列化的头信息字段,在new ObjectOutputStream的时候写入:
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); //设置该参数为true,下面会用到 if (extendedDebugInfo) { debugInfoStack = new DebugTraceInfoStack(); } else { debugInfoStack = null; } } protected void writeStreamHeader() throws IOException { bout.writeShort(STREAM_MAGIC);//写入一个序列化用到的魔法数 bout.writeShort(STREAM_VERSION);//写入一个序列化的版本号 } public interface ObjectStreamConstants { /** * Magic number that is written to the stream header. */ final static short STREAM_MAGIC = (short)0xaced; /** * Version number that is written to the stream header. */ final static short STREAM_VERSION = 5;
接下来的两个字节0x770E是在ObjectOutputStream close或者flush的时候会调用bout的close方法写入两个信息,
0x77是序列化内容长度小于0xff时设置的,0x0E是内容的长度。
public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants { public void close() throws IOException { flush(); clear(); bout.close(); }
然后bout.close()方法调用:
private static class BlockDataOutputStream extends OutputStream implements DataOutput{ public void flush() throws IOException { drain(); out.flush(); } public void close() throws IOException { flush(); out.close(); } void drain() throws IOException { if (pos == 0) { return; } if (blkmode) {//这里为true writeBlockHeader(pos);//然后写入关于序列化内容的两个信息 } out.write(buf, 0, pos); pos = 0; } private void writeBlockHeader(int len) throws IOException { if (len <= 0xFF) { hbuf[0] = TC_BLOCKDATA; //长度小于0xff时,写入BLOCKDATA的头 == 0x77 hbuf[1] = (byte) len;//写入内容的长度 out.write(hbuf, 0, 2); } else { hbuf[0] = TC_BLOCKDATALONG; Bits.putInt(hbuf, 1, len); out.write(hbuf, 0, 5); } }
然后0x0000007B就是123了,0x0008是后面字符串的长度,接着0x7374723132333435就是字符串str12345了。
我们再试试一个另外一个,我们写入一个bean
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class SeriableTest { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("e:\\log\\aa.txt"))); out.writeObject(new Bean()); out.close(); ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("e:\\log\\aa.txt"))); Bean bean = (Bean) in.readObject(); System.out.println(bean.a + " " + bean.b); } } class Bean implements Serializable{ private static final long serialVersionUID = -1710202516612576460L; int a = 1; int b = 2; }
输出为:
这里 前面的ACED0005跟上面的一样
73表示这个一个TC_OBJECT对象
/**
* new Object.
*/
final static byte TC_OBJECT = (byte)0x73;
private void writeOrdinaryObject(Object obj,
ObjectStreamClass desc, boolean unshared) 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); //写入class对象的描述信息 handles.assign(unshared ? null : obj); if (desc.isExternalizable() && !desc.isProxy()) { writeExternalData((Externalizable) obj); } else { writeSerialData(obj, desc); //写入实例对象的数据 } } finally { if (extendedDebugInfo) { debugInfoStack.pop(); } } }
我们看下writeClassDesc(desc, false); //写入class对象的描述信息的
下面写入的数据位:72
private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared) throws IOException { bout.writeByte(TC_CLASSDESC); //final static byte TC_CLASSDESC = (byte)0x72; 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); annotateClass(cl); //子类可以重载该方法自己写入class对象 bout.setBlockDataMode(false); bout.writeByte(TC_ENDBLOCKDATA);// final static byte TC_ENDBLOCKDATA = (byte)0x78; writeClassDesc(desc.getSuperDesc(), false);//写入父类的信息 没有父类,最后写入0x70 }
writeClassDescriptor最后调用的是下面这个方法:
写入的是 00 08 67 72 67 2E 42 65 61 6E E8 44 23 DF 47 54 0B 34 02 00 02 49 00 01 61 49 00 01 62
void writeNonProxy(ObjectOutputStream out) throws IOException {
out.writeUTF(name);//写入类的完整名称,我这里是org.Bean 2byte+7byte
对应16进制为00 08 67 72 67 2E 42 65 61 6E
out.writeLong(getSerialVersionUID());//写入bean的序列化id 8byte 对应为E8 44 23 DF 47 54 0B 34
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); //写入类的flag信息,1byte 02
out.writeShort(fields.length);//写入对象的序列化字段个数 这里=2,a,b, 2byte 00 02
for (int i = 0; i < fields.length; i++) {//遍历flag,写入每个flag的信息 49 00 01 61 49 00 01 62
ObjectStreamField f = fields[i];
out.writeByte(f.getTypeCode()); //1byte
out.writeUTF(f.getName()); //(2byte + 1byte) + (2byte+1byte)
if (!f.isPrimitive()) {//如果不是基本类型,写还需写入基本类型的信息,这里a和b都是基本类型
out.writeTypeString(f.getTypeString());
}
}
}
最后就是写入每个字段的值了 ,最后写入00 00 00 01 00 00 00 02
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()); //写入00 00 00 01 00 00 00 02 } finally { if (extendedDebugInfo) { debugInfoStack.pop(); } } } }
发表评论
-
对字符串进行验证之前先进行规范化
2013-09-17 23:18 13886对字符串进行验证之前先进行规范化 应用系统中经常对字 ... -
使用telnet连接到基于spring的应用上执行容器中的bean的任意方法
2013-08-08 09:17 1432使用telnet连接到基于spring的应用上执行容器中 ... -
jdk7和8的一些新特性介绍
2013-07-06 16:07 10070更多ppt内容请查看:htt ... -
java对于接口和抽象类的代理实现,不需要有具体实现类
2013-06-12 09:50 2907原文链接:http://www.javaarch.net/j ... -
Java EE 7中对WebSocket 1.0的支持
2013-06-05 09:27 3799原文链接:http://www.javaarch.n ... -
Java Web使用swfobject调用flex图表
2013-05-28 19:05 1079Java Web使用swfobject调用 ... -
spring使用PropertyPlaceholderConfigurer扩展来满足不同环境的参数配置
2013-05-21 15:57 3288spring使用PropertyPlaceholderCon ... -
java国际化
2013-05-20 20:57 4438java国际化 本文来自:http://www.j ... -
RSS feeds with Java
2013-05-20 20:52 1184RSS feeds with Java 原文来自:htt ... -
使用ibatis将数据库从oracle迁移到mysql的几个修改点
2013-04-29 10:40 1634我们项目在公司的大战略下需要从oracle ... -
线上机器jvm dump分析脚本
2013-04-19 10:48 2863#!/bin/sh DUMP_PIDS=`p ... -
eclipse远程部署,静态文件实时同步插件
2013-04-06 20:18 5418eclipse 远程文件实时同步,eclipse远程 ... -
java价格处理的一个问题
2013-03-26 21:21 1794我们经常会处理一些价格,比如从运营上传的文件中将某 ... -
java 服务降级开关设计思路
2013-03-23 16:35 3720java 服务屏蔽开关系统,可以手工降级服务,关闭服 ... -
poi解析excel内存溢出
2013-03-20 22:21 6344真是悲剧啊,一个破内部使用系统20多个人使用的后 ... -
简单web安全框架
2013-03-16 11:56 1498web安全框架,主要用servlet filter方 ... -
基于servlet的简单的页面缓存框架
2013-03-11 19:27 1177基于servlet的页面级缓存框架的基本用法: 代码参考: ... -
Eclipse使用过程中出现java.lang.NoClassDefFoundError的解决方案
2013-02-01 17:22 1474如果jdk,classpath设置正确,突然在eclipse ... -
jetty对于包的加载顺序的处理
2013-01-28 22:58 40651.问题 今天在本地和测试环境用jet ... -
hsqldb源码分析系列6之事务处理
2013-01-20 15:20 1676在session的 public Result ...
相关推荐
Java序列化API提供一种处理对象序列化的标准机制。在这里你能学到如何序列化一个对象,什么时候需要序列化以及Java序列化的算法,我们用一个实例来示范序列化以后的字节是如何描述一个对象的信息的。……
Java序列化的机制和原理[归类].pdf
有关Java对象的序列化和反序列化也算是Java基础的一部分,下面对Java序列化的机制和原理进行一些介绍
序列化和反序列化 继承、封装、多态的实现原理 容器 Java集合类总结 Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解2:Queue和LinkedList Java集合详解3:Iterator,fail-fast机制...
10 10序列化与对象克隆 10 11文件锁FileLock 10 12Process类中的流 10 13带进度条的输入流 习题 第11章Java网络的基本知识 11 1使用URL 11 2读取URL中的资源 11 3显示URL资源中的HTML文件 11 4处理超链接 11 5...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
如何实现Java序列化与反序列化.序列化和反序列化使用的API 如何实现Java中的一个对象中某一个属性不被序列化,如何实现呢? Java中堆内存和栈内存区别 讲一讲反射,主要是概念,都在哪需要反射机制 JSP中有个...
反序列化漏洞的本质是反序列化机制打破了数据和对象的边界,导致攻击者注入的恶意序列化数据在反序列化过程中被还原成对象,控制了对象可能在目标系统上面执行攻击代码,而不可信的输入和未检测反序列化对象的...
理解通信协议传输过程中的序列化和反序列化机制 基于框架的RPC通信技术 WebService/ApacheCXF RMI/Spring RMI Hession 传统RPC技术在大型分布式架构下面临的问题 分布式架构下的RPC解决方案 Zookeeper ...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
序列化和反序列化 继承封装多态的实现原理 集合类 Java集合类总结 Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解:Queue和LinkedList Java集合详解:迭代器,快速失败机制与比较器...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
【大厂面试题总结】JavaSE面试题总结详细教程: 目录: 递归算法之输出某个目录下所有文件和子目录列表 泛型中extends和super的区别 ...java序列化方式 java中实现多态的机制 string常量池和intern韩雅茹
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
【大厂面试题总结】JavaSE面试题合集及其答案,基本包括javaSE所有知识点和详细解释 。 JavaSE面试题总结详细教程: 目录: 递归算法之输出某个目录下所有...java序列化方式 java中实现多态的机制 string常量池和intern
B.2 运用反射机制来持久化Java对象 附录C 用XDoclet工具生成映射文件 C.1 创建带有@hibernate标记的Java源文件 C.2 建立项目的目录结构 C.3 运行XDoclet工具 附录D 发布和运行netstore应用 D.1 运行...
密钥 Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存...