标签:
Serializable & Parcelable这两种序列化方法是Android中经常使用的方法,Serializable是Android从Java中继承过来的,Parcelable是Android自己提供的方法,Google是推荐使用Parcelable,至于这两种方法的区别,下面通过对源码的分析来慢慢的了解。
在分析源码之前,首先还是说一下序列化在Android中使用的场景:
1)我们在四大组件之间使用intente来传递数据,intente中所传递的数据是需要序列化的
2)binder,binder是IPC机制中是很重要的,binder中所传递的数据也是需要序列化的
3)还有我们经常要把一些数据持久化到存储设备上,这些数据是需要序列化的
4)在网络中传递对象
好啦,现在我们开始对两种序列化方式的源码进行了解:
Serializable:
因为Serializable是一个标示接口,所以我们主要是对它的注解进行阅读
* Marks classes that can be serialized by {@link ObjectOutputStream} and
* deserialized by {@link ObjectInputStream}.这一句告诉我们,serializable是通过ObjectOutputStream、ObjectInputStream来完成序列化过程的
* <p><strong>Warning:</strong> this interface limits how its implementing
* classes can change in the future. By implementing {@code Serializable} you
* expose your flexible in-memory implementation details as a rigid binary
* representation. Simple code changes--like renaming private fields--are
* not safe when the changed class is serializable.这一句告诉我们,当实现Serializable接口的类中有代码变化,可能会导致序列化失败
<p>Every serializable class is assigned a version identifier called a {@code
* serialVersionUID}. By default, this identifier is computed by hashing the
* class declaration and its members. This identifier is included in the
* serialized form so that version conflicts can be detected during
* deserialization. If the local {@code serialVersionUID} differs from the
* {@code serialVersionUID} in the serialized data, deserialization will fail
* with an {@link InvalidClassException}.
*
* <p>You can avoid this failure by declaring an explicit {@code
* serialVersionUID}. Declaring an explicit {@code serialVersionUID} tells the
* serialization mechanism that the class is forward and backward compatible
* with all versions that share that {@code serialVersionUID}. Declaring a
* {@code serialVersionUID} looks like this: <pre> {@code
*
* private static final long serialVersionUID = 0L;
* }</pre>
* If you declare a {@code serialVersionUID}, you should increment it each
* time your class changes incompatibly with the previous version. Typically
* this is when you add, change or remove a non-transient field.当然我们也可以在类中自定义serialVersionUID,比如:
private static final long serialVersionUID = 0L;
这样的好处是,当类中的成员变量或者是方法增加、改变、移除的话,我们的反序列化依旧会成功,但是当类的结构有了翻天覆地的变化的时候,也会反序列化失败的。
上面有一句是:
Typically this is when you add, change or remove a non-transient field.告诉我们,被transient修饰的成员变量是不会参与序列化的。
* <p>You can take control of your serialized form by implementing these two
* methods with these exact signatures in your serializable classes:
* <pre> {@code
*
* private void writeObject(java.io.ObjectOutputStream out)
* throws IOException {
* // write 'this' to 'out'...
* }
*
* private void readObject(java.io.ObjectInputStream in)
* throws IOException, ClassNotFoundException {
* // populate the fields of 'this' from the data in 'in'...
* }
* }</pre>
先看writeObject:
它是ObjectOutputStream中的方法:
public final void writeObject(Object object) throws IOException {
writeObject(object, false);
}private void writeObject(Object object, boolean unshared) throws IOException {
boolean setOutput = (primitiveTypes == output);
if (setOutput) {
primitiveTypes = null;
}
// This is the specified behavior in JDK 1.2. Very bizarre way to allow
// behavior overriding.
if (subclassOverridingImplementation && !unshared) {
writeObjectOverride(object);
return;
}
try {
// First we need to flush primitive types if they were written
drain();
// Actual work, and class-based replacement should be computed
// if needed.
writeObjectInternal(object, unshared, true, true);
if (setOutput) {
primitiveTypes = output;
}
} catch (IOException ioEx1) {
// This will make it pass through until the top caller. Only the top caller writes the
// exception (where it can).
if (nestedLevels == 0) {
try {
writeNewException(ioEx1);
} catch (IOException ioEx2) {
// If writing the exception to the output stream causes another exception there
// is no need to propagate the second exception or generate a third exception,
// both of which might obscure details of the root cause.
}
}
throw ioEx1; // and then we propagate the original exception
}
}
writeObjectInternal(object, unshared, true, true);
private int writeObjectInternal(Object object, boolean unshared,
boolean computeClassBasedReplacement,
boolean computeStreamReplacement) throws IOException {
...
f (!(enableReplace && computeStreamReplacement)) {
// Is it a Class ?
if (objClass == ObjectStreamClass.CLASSCLASS) {
return writeNewClass((Class<?>) object, unshared);
}
// Is it an ObjectStreamClass ?
if (objClass == ObjectStreamClass.OBJECTSTREAMCLASSCLASS) {
return writeClassDesc((ObjectStreamClass) object, unshared);
}
}
''''
}再看readObject:
readObject是ObjectInoutStream中的方法:
public final Object readObject() throws OptionalDataException,
ClassNotFoundException, IOException {
return readObject(false);
} private Object readObject(boolean unshared) throws OptionalDataException,
ClassNotFoundException, IOException {
...
Object result;
try {
// We need this so we can tell when we are returning to the
// original/outside caller
if (++nestedLevels == 1) {
// Remember the caller's class loader
callerClassLoader = VMStack.getClosestUserClassLoader(bootstrapLoader, systemLoader);
}
result = readNonPrimitiveContent(unshared);
if (restoreInput) {
primitiveData = input;
}
}
...
}调用readNonPrimitiveContent();
private Object readNonPrimitiveContent(boolean unshared)
throws ClassNotFoundException, IOException {
checkReadPrimitiveTypes();
if (primitiveData.available() > 0) {
OptionalDataException e = new OptionalDataException();
e.length = primitiveData.available();
throw e;
}
do {
byte tc = nextTC();
switch (tc) {
case TC_CLASS:
return readNewClass(unshared);
case TC_CLASSDESC:
return readNewClassDesc(unshared);
case TC_ARRAY:
return readNewArray(unshared);
case TC_OBJECT:
return readNewObject(unshared);
case TC_STRING:
return readNewString(unshared);
case TC_LONGSTRING:
return readNewLongString(unshared);
case TC_ENUM:
return readEnum(unshared);
case TC_REFERENCE:
if (unshared) {
readNewHandle();
throw new InvalidObjectException("Unshared read of back reference");
}
return readCyclicReference();
case TC_NULL:
return null;
case TC_EXCEPTION:
Exception exc = readException();
throw new WriteAbortedException("Read an exception", exc);
case TC_RESET:
resetState();
break;
case TC_ENDBLOCKDATA: // Can occur reading class annotation
pushbackTC();
OptionalDataException e = new OptionalDataException();
e.eof = true;
throw e;
default:
throw corruptStream(tc);
}
// Only TC_RESET falls through
} while (true);
} private byte nextTC() throws IOException {
if (hasPushbackTC) {
hasPushbackTC = false; // We are consuming it
} else {
// Just in case a later call decides to really push it back,
// we don't require the caller to pass it as parameter
pushbackTC = input.readByte();
}
return pushbackTC;
}可以看出在序列化中要进行大量的I\O的操作,而且里面还有用到反射的机制,对资源的消耗也比较大
Parcelable:
老规矩,先看一下注解:
* Interface for classes whose instances can be written to
* and restored from a {@link Parcel}. Classes implementing the Parcelable
* interface must also have a static field called <code>CREATOR</code>, which
* is an object implementing the {@link Parcelable.Creator Parcelable.Creator}
* interface.这句话意思是,对象能够通过Parcel来进行序列化和反序列化,而且重要的是,在实现Parcelable中必须要有一个成员变量,而且还要被 static field来修饰,类型为Parcelable.Creator,它是Parcelable中的一个内部接口
<p>A typical implementation of Parcelable is:</p>
*
* <pre>
* public class MyParcelable implements Parcelable {
* private int mData;
*
* public int describeContents() {
* return 0;
* }
*
* public void writeToParcel(Parcel out, int flags) {
* out.writeInt(mData);
* }
*
* public static final Parcelable.Creator<MyParcelable> CREATOR
* = new Parcelable.Creator<MyParcelable>() {
* public MyParcelable createFromParcel(Parcel in) {
* return new MyParcelable(in);
* }
*
* public MyParcelable[] newArray(int size) {
* return new MyParcelable[size];
* }
* };
*
* private MyParcelable(Parcel in) {
* mData = in.readInt();
* }
* }</pre>public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;
/**
* Describe the kinds of special objects contained in this Parcelable's
* marshalled representation.
*
* @return a bitmask indicating the set of special object types marshalled
* by the Parcelable.
*/
public int describeContents();
文件描述符,当对象有文件描述符时就返回1(CONTENTS_FILE_DESCRIPTOP),否则就返回0,大多数情况就返回0
/**
* Flatten this object in to a Parcel.
*
* @param dest The Parcel in which the object should be written.
* @param flags Additional flags about how the object should be written.
* May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
*/
public void writeToParcel(Parcel dest, int flags);该方法是将对象写入到序列化结构中,dest:对象应该要被写入的序列化结构的容器
flags:有两种结果,为1(PARCELABLE_WRITE_RETURN_VALUE)从字面意 思可以看到就是要求要返回对象,大多数情况下是为0的。
/**
* Interface that must be implemented and provided as a public CREATOR
* field that generates instances of your Parcelable class from a Parcel.
*/
public interface Creator<T> {
}然后看Creator中的两个接口:
/**
* Create a new instance of the Parcelable class, instantiating it
* from the given Parcel whose data had previously been written by
* {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.
*
* @param source The Parcel to read the object's data from.
* @return Returns a new instance of the Parcelable class.
*/
public T createFromParcel(Parcel source);这个方法就是从Parcel中构造出一个实现了Parcelable的类的实例,一般我们实现是通过类的构造方法中实现的:
return new T(source);
/**
* Create a new array of the Parcelable class.
*
* @param size Size of the array.
* @return Returns an array of the Parcelable class, with every entry
* initialized to null.
*/
public T[] newArray(int size);return new T[size];
在Parcelable中实现序列化和反序列化主要是通过Parcel来实现的,对于Parcel,可以去看
最后进行一下总结:
| 优点 | 缺点 | |
| Serializable | 1)实现起来简单 2)通过自定义serialVersionUID 可以 减少反序列化失败的发生 |
1)反射 2)大量的I\O操作,反序列化速度慢 2)耗资源 |
| parcelable | 1)速度快 | 1)实现难,难以阅读 2)难以维护 |
最后,谢谢大家的观看!
android——Serializable & Parcelable
标签:
原文地址:http://blog.csdn.net/qq_22218005/article/details/51330722