Serializable对象/数据序列化
一、Serializable详解
- Serializalbe这种简单机制是通过牺牲掉执行性能为代价换来的。通过Serializable将对象持久化存储,也可以通过Bundle传递Serializable的序列化数据。
- 什么是序列化:把一个Object对象的所有信息表示成一个字节序列,这包括Class信息、继承关系、访问权限、变量类型以及数值信息等。
(1)Serializable实现类
public class Person implements Serializable {
public String name;
public static int age;
public transient int sex;
public Person(String name) {
this.name = name;
}
}
- 将Person对象序列化与反序列化
Person person = new Person();
//定义一个字节数组输出流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream outputStream;
try {
outputStream = new ObjectOutputStream(byteArrayOutputStream);
//将指定的对象写入字节数组输出,进行序列化
outputStream.writeObject(person);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
byte[] bytes = byteArrayOutputStream.toByteArray();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream;
try {
//执行反序列化,从流中读取对象
objectInputStream = new ObjectInputStream(byteArrayInputStream);
Person person1 = (Person) objectInputStream.readObject();
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
(2)ObjectOutputStream源码
public ObjectOutputStream(OutputStream out) throws IOException {
//检查继承权限
verifySubclass();
//构造一个BlockDataOutputStream用于向out写入序列化数据
bout = new BlockDataOutputStream(out);
//构造一个大小为10,负载因子为3的HandleTable和ReplaceTable
handles = new HandleTable(10, (float) 3.00);
subs = new ReplaceTable(10, (float) 3.00);
//有参构造方法默认为false,
enableOverride = false;
writeStreamHeader();
//将缓存模式打开,写入数据时先写入缓冲区
bout.setBlockDataMode(true);
if (extendedDebugInfo) {
debugInfoStack = new DebugTraceInfoStack();
} else {
debugInfoStack = null;
}
}
public final void writeObject(Object obj) throws IOException {
//判断是否需要重写writeObject(),无参构造函数该变量默认为true,有参为false。
if (enableOverride) {
writeObjectOverride(obj);
return;
}
try {
writeObject0(obj, false);
} catch (IOException ex) {
if (depth == 0) {
try {
writeFatalException(ex);
} catch (IOException ex2) {
}
}
throw ex;
}
}
private void writeObject0(Object obj, boolean unshared)
throws IOException
{
boolean oldMode = bout.setBlockDataMode(false);
depth++;
try {
//处理以前写入的和不可替换的对象
int h;
if ((obj = subs.lookup(obj)) == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
}
Object orig = obj;
Class<?> cl = obj.getClass();
ObjectStreamClass desc;
Class repCl;
//ObjectStreamClass表示序列化对象的class详细信息
desc = ObjectStreamClass.lookup(cl, true);
if (desc.hasWriteReplaceMethod() &&
(obj = desc.invokeWriteReplace(obj)) != null &&
(repCl = obj.getClass()) != cl)
{
cl = repCl;
//生成替换对象类型的ObjectStreamClass
desc = ObjectStreamClass.lookup(cl, true);
}
if (enableReplace) {
Object rep = replaceObject(obj);
if (rep != obj && rep != null) {
cl = rep.getClass();
desc = ObjectStreamClass.lookup(cl, true);
}
//重新赋值要序列化的对象
obj = rep;
}
//如果替换了对象,请再次运行原始检查
if (obj != orig) {
subs.assign(orig, obj);
if (obj == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
}
}
if (obj instanceof Class) {
writeClass((Class) obj, unshared);
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
// END Android-changed: Make Class and ObjectStreamClass replaceable.
} else 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) {
//我们只看实现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);
}
}
(3)ObjectInputStream源码
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
enableOverride = false;
readStreamHeader();
bin.setBlockDataMode(true);
}
public final Object readObject()
throws IOException, ClassNotFoundException
{
if (enableOverride) {
return readObjectOverride();
}
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
Object obj = readObject0(false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
}
private Object readObject0(boolean unshared) throws IOException {
boolean oldMode = bin.getBlockDataMode();
if (oldMode) {
int remain = bin.currentBlockRemaining();
if (remain > 0) {
throw new OptionalDataException(remain);
} else if (defaultDataEnd) {
/*
* Fix for 4360508: stream is currently at the end of a field
* value block written via default serialization; since there
* is no terminating TC_ENDBLOCKDATA tag, simulate
* end-of-custom-data behavior explicitly.
*/
throw new OptionalDataException(true);
}
bin.setBlockDataMode(false);
}
byte tc;
while ((tc = bin.peekByte()) == TC_RESET) {
bin.readByte();
handleReset();
}
depth++;
try {
switch (tc) {
case TC_NULL:
return readNull();
case TC_REFERENCE:
return readHandle(unshared);
case TC_CLASS:
return readClass(unshared);
case TC_CLASSDESC:
case TC_PROXYCLASSDESC:
return readClassDesc(unshared);
case TC_STRING:
case TC_LONGSTRING:
return checkResolve(readString(unshared));
case TC_ARRAY:
return checkResolve(readArray(unshared));
case TC_ENUM:
return checkResolve(readEnum(unshared));
case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));
case TC_EXCEPTION:
IOException ex = readFatalException();
throw new WriteAbortedException("writing aborted", ex);
case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
if (oldMode) {
bin.setBlockDataMode(true);
bin.peek(); // force header read
throw new OptionalDataException(
bin.currentBlockRemaining());
} else {
throw new StreamCorruptedException(
"unexpected block data");
}
case TC_ENDBLOCKDATA:
if (oldMode) {
throw new OptionalDataException(true);
} else {
throw new StreamCorruptedException(
"unexpected end of block data");
}
default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
} finally {
depth--;
bin.setBlockDataMode(oldMode);
}
}
-
Serializable 序列化支持替代默认流程,它会先反射判断是否存在我们自己实现的序列化方法 writeObject 或 反序列化方法 readObject。通过这两个方法,我们可以对某些字段做一些特殊修改,也可以实现序列化的加密功能。
-
我们可以通过 writeReplace 和 readResolve 方法实现自定义返回的序列化实例。通过它们实现对序列化的版本兼容,例如通过 readResolve 方法可以把老版本的序列化对象转换成新版本的对象类型。
-
Serializable 整个序列化过程使用了大量的反射和临时变量,而且在序列化对象的时候,不仅会序列化当前对象本身,还需要递归序列化引用的其它对象。
-
不被序列化字段。类的 static 变量以及被声明为 transient 的字段,默认的序列化机制都会忽略该字段,不会进行序列化存储。当然我们也可以使用进阶的 writeObject 和 readObject 方法做自定义的序列化存储。
-
serialVersionUID。在类实现了 Serializable 接口后,我们需要添加一个 Serial Version ID,它相当于类的版本号。这个 ID 我们可以显示声明也可以让编译器自己计算。通常建议显示声明会更加稳妥,因为隐士声明假如类发生了一点点变化,进行反序列化都会由于 serialVersionUID 改变而导致 InvalidClassException 异常。
-
构造方法。Serializable 的反序列化默认是不会执行构造函数的,它是根据数据流中对 Object 的描述信息创建对象的。如果一些逻辑依赖构造函数,就可能会出现问题,例如一个静态变量只在构造方法中赋值,当然我们也可以通过进阶的自定义反序列化修改。