概念
序列化:
将数据结构或者对象转换成二进制数据的过程;
反序列化:
将二进制数据转换成数据结构或者对象的过程。
应用场景
1.网络传输
2.进程间通讯(进程间传递数据)
3.intent传输数据
4.数据持久化(保存到文件/数据库)
序列化方案
1.Serializable
空接口,起到标识作用,最简单的序列化方式,直接实现该接口即可,不需要实现任何方法。
细节
1. serialVersionUID
控制版本,主要是在反序列化的时候,jvm会对比二进制中的servialVersionUID和本地类文件中的servialVersionUID是否相同,相同则进行反序列化过程,不同直接抛出异常:
Exception in thread "main" java.io.InvalidClassException: com.ayy.enjoystudyhomework.serialiable.Student; local class incompatible: stream classdesc serialVersionUID = 994478117524975274, local class serialVersionUID = 994478117524975272
注意: 只要servialVersionUID相同就不会抛出以上异常,即使修改了类中的字段。
那么什么场景加,什么场景不加呢?
如果不手动指定 serialVersionUID,那么如果反序列化时相比序列化时的类结构发生了变动,那么jvm会重新计算(jvm自己的算法) serialVersionUID,导致序列化时的类和当前类的 serialVersionUID 值不一致,反序列化失败,抛出上述异常。
自动生成servialVersionUID
理解serialVersionUID
2.所有字段都要可序列化
基础类型(String,int,boolean,char等)已经默认实现的Serializable,如果类中有未实现Serializable的属性,序列化的时候会抛出以下异常:
Exception in thread "main" java.io.NotSerializableException: com.ayy.enjoystudyhomework.serialiable.Tag
3.transient
如果有些字段我就是不想实现序列化呢?可以忽略:
java:使用transient关键字修饰
koltin:使用@Transient注解
被transient(瞬间)修饰的字段或方法都是不被序列化的,也就是保存到本地和从本地读取的时候都不会操作这个字段。
4.静态变量不会被序列化
被static修饰的变量不会被序列化,因为我们序列化的是对象实例吗,而静态变量是属于类的。
5.自定义序列化和反序列化
类中定义writeObject和readObject方法可以自定义序列化逻辑。不太常用,了解即可。
从序列化流程图中可以看出我们可以干预其流程:
6.单例序列化
序列化和反序列化或破坏单例的唯一性。解决方法是在单例中定义readResolve方法返回单例对象:
public class SingleTon {
private volatile static SingleTon instance;
public static SingleTon getInstance() {
if (instance == null) {
synchronized (SingleTon.class) {
if (instance == null) {
instance = new SingleTon();
}
}
}
return instance;
}
//定义此方法即可
public SingleTon readResolve() {
return this;
}
}
2.Externalizable
此接口继承自Serializable,可定制化序列化和反序列化过程,类似上面细节中的第五点
3.Parcelable
安卓特有的序列化方式,底层做了优化,性能较好,内存开销较小。
实现此接口,代码提示快捷键生成对应代码。
class Dog(var name: String?, var age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeInt(age)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Dog> {
override fun createFromParcel(parcel: Parcel): Dog {
return Dog(parcel)
}
override fun newArray(size: Int): Array<Dog?> {
return arrayOfNulls(size)
}
}
}
Serializable和Parcelable那个性能比较好?为什么?
1.Parcelable性能相对较好
2.内存上Parcelable较小
3.Serializable序列化过程中使用了反射,会产生很多临时变量,影响性能
4.安卓专有,基于binder机制
遗留问题:
1.Parcelable不能很好的保证数据的持续性,为什么?
2.Parce还需深入理解
3.多引用问题:reser&&writeUnshare
总结
1.保存数据到 SD 卡,网络传输时使用 Serializable 即可,虽然效率差一些,好在使用方便。
2.运行时数据传递建议使用 Parcelable,比如 Intent,Bundle 等,Android 底层做了优化处理,效率很高。