Serializable与Parcelable区别
2016-03-14 14:19
417 查看
Serializable是Java中序列化的接口,主要用于ObjectInputStream和ObjectOutputStream进行对象读写。关于Serializable的相关注意点大概如下:序列化ID,静态变量序列化,序列化存储规则,单例模式序列化等
①序列化ID:调整类结构后,其serialVersionUID若未修改,反序列化过程中不会报异常,但获取某个属性值时可能会null;seriaVersionUID修该,则会报异常。如果没有显式的声明serialVersionUID,对于jvm来说不同的类结构其seriaVersionUID也会不同,因此也会报异常。
②静态变量序列化:序列化时不保存静态变量,若将对象序列化后修改其静态变量值,反序列化后取出的静态变量值不是序列化时的值。静态变量是类的状态,序列化只保存对象的状态。
③序列化存储规则:如果将对象连续两次写入磁盘,再依次读取生成两个对象,这两个对象是相等的。序列化存储规则,若是存储两个相同对象则只在第一次存储内容,第二次存储的是对象的引用,存储空间并不会翻倍,这样做的好处是极大的节约了存储空间。若第二次存储修改了对象的状态,依然存储对象的引用,这样读取时生成的两个对象还是会相等。
④单例模式序列化:反序列化时会调用类构造器,会再次创造一个对象,这用就无法达到单例的效果,这时需要重写readResolve()方法.
为什么序列化会破坏单例模式?
ObjectInputStream中有这样一段代码,isInstantiable若实现序列化会desc.newInstance()创建一个新的对象,但后面判断(desc.hasReadResolveMethod())若实现了readResolve方法则会返回true,然后再通过反射的方式调用要被反序列化的类的readResolve方法。因此要保证序列化不会破坏就需要重写readResolve()方法返回本身。
Parcelable是为了提高序列化速度,并且占用内存小,可以高效的在组件间和进程间传输数据。需要重写writeToParcel(Parcel in,int flag),describeContents(),还用构造器等。若类中成员有引用数据类型(Class)变量,该引用类也要实现Parcelable接口。
Serializable序列化适合IO操作,实现简单,只要实现Serializable借口就可以,不需要实现任何方法,无特殊情况下可以使用默认生成的seriaVersionUID。
Parcelable适合内存中数据传输,其转化效率快,节约内存。Android组件间通讯可以实现该接口。但其实现比较繁琐,如果使用AndroidStudio开发,可以使用Android parcelable code generator这个插件自动生成(注意其成员变量若为Class,则先对该成员变量的class自动实现parcelable,否则会导致序列化出错)。
①序列化ID:调整类结构后,其serialVersionUID若未修改,反序列化过程中不会报异常,但获取某个属性值时可能会null;seriaVersionUID修该,则会报异常。如果没有显式的声明serialVersionUID,对于jvm来说不同的类结构其seriaVersionUID也会不同,因此也会报异常。
②静态变量序列化:序列化时不保存静态变量,若将对象序列化后修改其静态变量值,反序列化后取出的静态变量值不是序列化时的值。静态变量是类的状态,序列化只保存对象的状态。
③序列化存储规则:如果将对象连续两次写入磁盘,再依次读取生成两个对象,这两个对象是相等的。序列化存储规则,若是存储两个相同对象则只在第一次存储内容,第二次存储的是对象的引用,存储空间并不会翻倍,这样做的好处是极大的节约了存储空间。若第二次存储修改了对象的状态,依然存储对象的引用,这样读取时生成的两个对象还是会相等。
④单例模式序列化:反序列化时会调用类构造器,会再次创造一个对象,这用就无法达到单例的效果,这时需要重写readResolve()方法.
public Object readResolve throws ObjectStreamException{ return this; }
为什么序列化会破坏单例模式?
Object obj; try { obj = desc.isInstantiable() ? desc.newInstance() : null; } catch (Exception ex) { throw (IOException) new InvalidClassException( desc.forClass().getName(), "unable to create instance").initCause(ex); } 。。。。 if (obj != null && handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()) { Object rep = desc.invokeReadResolve(obj); if (unshared && rep.getClass().isArray()) { rep = cloneArray(rep); } if (rep != obj) { handles.setObject(passHandle, obj = rep); } }
ObjectInputStream中有这样一段代码,isInstantiable若实现序列化会desc.newInstance()创建一个新的对象,但后面判断(desc.hasReadResolveMethod())若实现了readResolve方法则会返回true,然后再通过反射的方式调用要被反序列化的类的readResolve方法。因此要保证序列化不会破坏就需要重写readResolve()方法返回本身。
Parcelable是为了提高序列化速度,并且占用内存小,可以高效的在组件间和进程间传输数据。需要重写writeToParcel(Parcel in,int flag),describeContents(),还用构造器等。若类中成员有引用数据类型(Class)变量,该引用类也要实现Parcelable接口。
@Override public void writeToParcel(Parcel in,int flag){ in.writeInt(this.a); in.writeString(this.b); in.writeByte(this.c ? (byte)1:(byte)0); in.writeParcelable(obj,0); } @Override public int describeContent{ return 0; } public static final Parcelable.Creator<XX> CREATE = new Parcelable.creator<XX>{ @Override public XX createFromParcel(Parcel source){ return new XX(source); } @Override public XX[] newArray(int size){ return new XX[size]; } }; public XX(){ } public XX(Parcel in){ this.a = in.readInt(); this.b = in.readString(); this.c = in.readByte != 0; this,onj = in.readParcelable(Obj.class.getClassLoader()); }
Serializable序列化适合IO操作,实现简单,只要实现Serializable借口就可以,不需要实现任何方法,无特殊情况下可以使用默认生成的seriaVersionUID。
Parcelable适合内存中数据传输,其转化效率快,节约内存。Android组件间通讯可以实现该接口。但其实现比较繁琐,如果使用AndroidStudio开发,可以使用Android parcelable code generator这个插件自动生成(注意其成员变量若为Class,则先对该成员变量的class自动实现parcelable,否则会导致序列化出错)。
相关文章推荐
- hibernate的配置
- C++_C风格字符串
- 网页布局基础--简介
- iOS开发之简单实现圆形进度条
- spring常用注解
- swift - map() 与flatMap()
- ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
- WebView点击图片看大图效果
- 解决 service iptables start 无法启动的问题
- try catch 好不好
- VS2008引入头文件包含目录和lib库目录
- C#中用RSA算法生成公钥和私钥 openssl RSA密钥的生成与配置
- 应用交付的变革者Docker
- Win7系统出现蓝屏代码0x000000a的原因及解决方法
- 并发编程
- squid 介绍
- Maven学习笔记
- java微信开发-配置SpringMVC
- 三大框架整合
- iOS 图标、图形尺寸?