序列化反序列化Serializable和Parcelable

Serializable的作用: 是java提供的一个序列化接口,用来为对象提供标准的序列化和反序列化操作。使用Serializable做序列化比较简单。
使用方式:

  • 直接实现Serializable接口
  • 声明一个静态值serialVersionUID。这个值并不是必须的,但是最好手动序列化。因为不设置这个值java会自动根据当前对象的hash生成一个值,但是这样容易引发一些问题,比如反序列化时程序崩溃。我们可以从后面的例子中看到。

注意: 1、序列化的时候会将Serializable的值一起写入文件,然后反序列化的时候再利用文件中的Serializable值和当前类的Serializable进行对比,如果不一致则会出现反序列化失败的问题,会直接程序崩溃,后面会举例。 2、静态变量是属于类不属于对象,所以不参与序列化过程。

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private String mUserName;
    private int mUserAge;

    public User(String userName, int userAge) {
        this.mUserName = userName;
        this.mUserAge = userAge;
    }

    public String getUserName() {
        return mUserName;
    }

    public int getUserAge() {
        return mUserAge;
    }
}
  • 如果不手动设置serialVersionUID 会发生什么?
public class User implements Serializable {
    private String mUserName;
    private int mUserAge;

    public User(String userName, int userAge) {
        this.mUserName = userName;
        this.mUserAge = userAge;
    }

    public String getUserName() {
        return mUserName;
    }

    public int getUserAge() {
        return mUserAge;
    }
}

public class Client {
    public static void main(String[] args) {
        User user = new User("Kyle", 18);
        //先序列化到一个文件中
        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
            out.writeObject(user);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

//        try {
//            ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
//            User userNew = (User) in.readObject();
//            in.close();
//            System.out.println("反序列化结果:" + userNew.getUserName() + userNew.getUserAge());
//        } catch (IOException e) {
//            e.printStackTrace();
//        } catch (ClassNotFoundException e) {
//            e.printStackTrace();
//        }
    }
}
public class Client {
    public static void main(String[] args) {
//        User user = new User("Kyle", 18);
//        try {
//            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
//            out.writeObject(user);
//            out.close();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
		//然后反序列化
        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
            User userNew = (User) in.readObject();
            in.close();
            System.out.println("反序列化结果:" + userNew.getUserName() + userNew.getUserAge());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

输出结果:
在这里插入图片描述
但是当后面我们在User类中增加一个字段时:由于此时在反序化时User类自动生成的Serializable已经自动改变,所以反序化就会失败,抛出JE。所以我们应该手动设置Serializable,一边可以最大化的反序化原始数据。

public class User implements Serializable {
    private String mUserName;
    private int mUserAge;
    private boolean mIsMale;

    public User(String userName, int userAge) {
        this.mUserName = userName;
        this.mUserAge = userAge;
    }

    public String getUserName() {
        return mUserName;
    }

    public int getUserAge() {
        return mUserAge;
    }
}

在这里插入图片描述
我们也可以在实验一下设置serialVersionUID的情况,即使我们新增加字段,还是可以反序列化出数据。

Parcelable的作用: Parcelable也是一个接口,是Android中提供的序列化和反序列化的方式,由于Serializable在开销较大,所以产生了Parcelable这种方式,可以方便在内存中进行序列化和数据传输。
使用:

public class User implements Parcelable{

    public int userId;
    public String userName;
    public boolean isMale;

    public Book book;

    public User(int userId, String userName, boolean isMale) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
    }

    protected User(Parcel in) {
        userId = in.readInt();
        userName = in.readString();
        isMale = in.readByte() != 0;
        book = in.readParcelable(Thread.currentThread().getContextClassLoader());
    }


    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(userId);
        dest.writeString(userName);
        dest.writeByte((byte) (isMale ? 1 : 0));
        dest.writeParcelable(book, 0);
    }
}

Parcelablede 方法说明:

方法功能
User(Parcel in)从序列化后的对象中创建原始对象
createFromParcel(Parcel in)从序列化后的对象中创建原始对象
newArray(int size)创建指定长度的原始对象数组
describeContents()返回当前对象的内容描述。如果含有文件描述符返回1, 否则返回0, 大部分情况都返回0
writeToParcel(Parcel dest, int flags)将当前对象写入序列化结构中,其中flags标识有两种值:0或者1.为1时标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0

Serializable与Parcelable的区别:

  1. 实现差异:Serializable实现起来很简单,Parcelable实现起来麻烦,需要实现一些方法
  2. 效率方面:Serializable效率较低,内存开销大,故经常用于持久化数据的序列化,如存储文件,网络传输等。而在内存间传输数据则应该使用Parcelable,效率高很多,如Android中的AIDL

Serializable与Parcelable的共同点:

  1. 无论是Parcelable还是Serializable,执行反序列操作后的对象都是新创建的,与原来的对象并不相同,只不过内容一样罢了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值