序列化

序列化:将数据结构或对象转换成二进制串(java指byte[ ] )的过程。

持久化:把数据结构或对象 存储到硬盘

序列化方案:1.Serializable;2.Parcelable 3. json,xml,protbuf … 广义的序列化

Serializable

Serializable 一般配合 ObjectOutputStream(序列化) 和 ObjectInputStream(反序列化) 一起使用

如果你已经序列化了一个类的对象,并且持久化保存;这时在该类添加了一个字段。再次通过持久化的数据进行反序列化时,会崩溃。

这是因为在序列化过程中,生成一个serialVersionUID的成员,做版本控制。而新旧类生成serialVersionUID时会不一样,导致序列化失败; InvalidClassException

可以自己在类中写死一个 private static final long serialVersionUID。

不同的编译器 实现该属性值的计算策略可能不同,从而造成虽然类没有改变,但是因为JVM不同,出现因类版本 不兼容而无法正确反序列化的现象出现

transient 关键字修饰的成员不会被序列化; 静态成员变量属于类不属于对象,所以不会参与序列化

如果尝试序列化实现可序列化的类的对象,但该对象包含对不可序列化类的引用,则在运行时将引发 不可序列化异常 NotSerializableExceptio

子类实现Serialiable父类没有实现,实例化子类要先调用父类构造 ,所以父类和子类必须要有无参构造,不然直接报错;这样只会序列化子类的信息,如果想序列化父类信息,需要自己重写readObject和writeObject方法实现;

反序列化一个类的过程中,它的非可序列化的属性将会调用无参构造函数重新创建

父类实现Serialiable,默认子类所有信息可以序列化,如果相让子类信息不能序列化:1.transient关键字控制部分信息不被实例化;2.自定义实例化过程,抛出异常,整个子类不能实例化。

如何自定义实例化过程:自己定义writeObject;readObject;readObjectNoData方法,自己实现自定义过程。这些方法会在 ObjectOutputStream.writeObject(saveThisObject), 和ObjectInputStream.readObject() 调用流程中被调用。会通过反射查看是否定义这些方法,如果定义了则调用,如果没定义,则执行原来的流程;

反序列化后的对象不会重新调用构造函数; 因为是从二进制直接解析出来的. 使用的是 Object 进行接收再强转, 因此不是原来的那个对象;是一个深拷贝, 前后对象的引用地址不同

序列化导致单例失效

Externalizable

(01) 实现Externalizable接口的类,不会像实现Serializable接口那样,会自动将数据保存。
(02) 实现Externalizable接口的类,必须实现writeExternal()和readExternal()接口!否则,程序无法正常编译!
(03) 实现Externalizable接口的类,必须定义不带参数的构造函数!否则,程序无法正常编译!
(04) writeExternal() 和 readExternal() 的方法都是public的,不是非常安全!

Parcelable

Parcel翻译过来是打包的意思,其实就是包装了我们需要传输 的数据,然后在Binder中传输,也就是用于跨进程传输数据 简单来说,Parcel提供了一套机制,可以将序列化之后的数据写入到一个共享内存中,其他进程通过 Parcel可以从这块共享内存中读出字节流,并反序列化成对象。

Parcel可以包含原始数据类型(用各种对应的方法写入,比如writeInt(),writeFloat()等),可以包含 Parcelable对象,它还包含了一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个 IBinder的代理IBinder。 Parcelable通过Parcel实现了read和write的方法,从而实现序列化和反序列化

性能比较 Parcelable强于Serializable

**在内存的使用中:**Serializable在序列化操作的时候会产生大量的临时变量,(原因是使用了反射机制)从而导致GC的频繁调用, 因此在性能上会稍微逊色 Parcelable是以Ibinder作为信息载体的.在内存上的开销比较小,

在读写数据的时候: Parcelable是在内存中直接进行读写,而Serializable是通过使用IO流的形式将数 据读写入在硬盘上.

在内存之间进行数据传递的时候,使用Parcelable; 数据的持久化方面仍然是使用Serializable

Intent 中的 Bundle 是使用 Binder 机制进行数据传送的。能使用的 Binder 的缓冲区是有大小限 制的(有些手机是 2 M)

Gson

基于事件驱动

常用注解
//字段名字控制 
@SerializedName("name") String a;//a => name
 @SerializedName(value = "name1", alternate = {"name2", "name3"})
//字段是否序列化控制 
//如果你使用new Gson()实例化一个对象的话,那么@Expose 的注解是无效的,User中的参数都是会参与反序列化或序列化。
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
class User0 {
    @Expose
    private String firstName;//参与序列化/反序列化

    @Expose(serialize = false)
    private String lastName;//参与反序列化

    @Expose(serialize = false, deserialize = true)
    private String emailAddress; //不参与

    private String password;//不参与
}

//版本控制
Gson gson = new GsonBuilder().setVersion(1.2).create();
private String lastName;//一直参与
@Since(1.0) private String emailAddress;//当前版本>=1.0时参与序列化/反序列化
@Until(1.1) private String emailAddress;//当前版本<=1.1时参加序列化/反序列化
//适配器控制
//方案1
@JsonAdapter(UserJsonAdapter.class)
class User {}
//方案二
 Gson gson = new GsonBuilder().registerTypeAdapter(GsonError1.class, new GsonError1Deserializer()).create();

registerTypeAdapter方法

两种方式自定义适配器:自定义TypeAdapter比较抽象,增加一个中间层JsonElement,更容易理解和操作。

1.JsonSerializer , JsonDeserializer
//序列化
JsonSerializer<T>  
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context);   
//反序列化
JsonDeserializer<T> 
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)throws JsonParseException;  

JsonElement是一个抽象类,代表着json串的某一个元素。 这个元素可以是一个Json(JsonObject)、可以是一个 数组(JsonArray)、可以是一个Java的基本类型(JsonPrimitive)、当然也可以为 null(JsonNull);他们都是JsonElement的子类。

2.TypeAdapter
TypeAdapter<T>  JsonWriter  JsonReader
class UserJsonAdapter extends TypeAdapter<User> {
    @Override
    public void write(JsonWriter out, User user) throws IOException {
        out.beginObject();
        out.name("name");
        out.value(user.firstName + " " + user.lastName);
        out.endObject();
    }
    @Override
    public User read(JsonReader in) throws IOException {
        in.beginObject();
        in.nextName();
        String[] nameParts = in.nextString().split(" ");
        in.endObject();
        return new User(nameParts[0], nameParts[1]);
    }
}
流程

每个类型都有与之对用的TypeAdapter实例,如果是自定的类,不设置adapter用反射调用初始化实例和字段;

//TypeAdapters.java
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
    
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值