编程知识 cdmana.com

Android序列化问题与思考

今天再来谈谈Android中的对象序列化,你了解多少呢?

序列化指的是什么?有什么用

序列化指的是讲对象变成有序的字节流,变成字节流之后才能进行传输存储等一系列操作。
反序列化就是序列化的相反操作,也就是把序列化生成的字节流转为我们内存的对象。

介绍下Android中两种序列化接口

Serializable

Java提供的一个序列化接口,是一个空接口,专门为对象提供序列化和反序列化操作。具体使用如下:

public class User implements Serializable { private static final long serialVersionUID=519067123721561165l;  private int id; public int getId() {  return id; } public void setId(int id) {  this.id = id; }}

实现Serializable接口,声明一个serialVersionUID

到这里可能有人就问了,不对啊,平时没有这个serialVersionUID啊。没错,serialVersionUID不是必须的,因为不写的话,系统会自动生成这个变量。它有什么用呢?当序列化的时候,系统会把当前类的serialVersionUID写入序列化的文件中,当反序列化的时候会去检测这个serialVersionUID,看他是否和当前类的serialVersionUID一致,一样则可以正常反序列化,如果不一样就会报错了。

所以这个serialVersionUID就是序列化和反序列化过程中的一个标识,代表一致性。不加的话会有什么影响?如果我们序列化后,改动了这个类的某些成员变量,那么serialVersionUID就会改变,这时候再拿之前序列化的数据来反序列化就会报错。所以如果我们手动指定serialVersionUID就能保证最大限度来恢复数据。

Serializable的实质其实是是把Java对象序列化为二进制文件,然后就能在进程之间传递,并且用于网络传输或者本地存储等一系列操作,因为他的本质就存储了文件。可以看看源码:

private void writeObject0(Object obj, boolean unshared) throws IOException{ ... try {    Object orig = obj;  Class<?> cl = obj.getClass();  ObjectStreamClass desc;    desc = ObjectStreamClass.lookup(cl, true);   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) {   writeOrdinaryObject(obj, desc, unshared);  } else {   if (extendedDebugInfo) {    throw new NotSerializableException(     cl.getName() + "\n" + debugInfoStack.toString());   } else {    throw new NotSerializableException(cl.getName());   }  } }  ...}private void writeOrdinaryObject(Object obj,          ObjectStreamClass desc,          boolean unshared)  throws IOException {  ...  try {   desc.checkSerialize();      //写入二进制文件,普通对象开头的魔数0x73   bout.writeByte(TC_OBJECT);   //写入对应的类的描述符,见底下源码   writeClassDesc(desc, false);      handles.assign(unshared ? null : obj);   if (desc.isExternalizable() && !desc.isProxy()) {    writeExternalData((Externalizable) obj);   } else {    writeSerialData(obj, desc);   }  } finally {   if (extendedDebugInfo) {    debugInfoStack.pop();   }  } } public long getSerialVersionUID() {  // 如果没有定义serialVersionUID,序列化机制就会调用一个函数根据类内部的属性等计算出一个hash值  if (suid == null) {   suid = AccessController.doPrivileged(    new PrivilegedAction<Long>() {     public Long run() {      return computeDefaultSUID(cl);     }    }   );  }  return suid.longValue(); }

可以看到是通过反射获取对象以及对象属性的相关信息,然后将数据写到了一个二进制文件,并且写入了序列化协议版本等等。
而获取·serialVersionUID·的逻辑也体现出来,如果id为空则会生成计算一个hash值。

Parcelable

Android自带的接口,使用起来要麻烦很多:需要实现Parcelable接口,重写describeContents(),writeToParcel(Parcel dest, @WriteFlags int flags),并添加一个静态成员变量CREATOR并实现Parcelable.Creator接口

public class User implements Parcelable {  private int id; protected User(Parcel in) {  id = in.read.........

版权声明
本文为[程序猿欧文]所创,转载请带上原文链接,感谢
https://my.oschina.net/mikeowen/blog/4714097

Scroll to Top