链接: https://www.cnblogs.com/zhwj184/archive/2012/06/02/3027487.html
https://www.cnblogs.com/zhwj184/archive/2012/06/04/3119633.html
我们查看下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();
}
}
}
}
下面我们来分析下序列化后的字节流内容:
先写一段测试代码:
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)
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
<span style="white-space: normal; background-color: #ffffff;">对应16进制为00 08 67 72 67 2E 42 65 61 6E </span>
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();
}
}
}
}