对象的序列化存储:Serializable 和 Parceable
在进行Android开发的时候我们有时候需要用到数据的持久化存储,或者在进程之间传递数据。其中就可能需要用到对象的序列化,经过序列化的对象之后可以通过Intent或者Boundle来传输了。接下来还是想些介绍下吧。
1.什么叫序列化,什么叫反序列化
序列化: 将数据结构或对象转换成二进制串的过程。反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。
简单来说,序列化就是将我们生成的对象进行存储起来(比如磁盘上),以用来将来使用或者在网络上进行传输,而反序列化呢,就是由我们的之前序列化生成的二进制串重新生成对象的过程。注意,这里我们反复说的序列化啦,反序列化啦,都是针对的对象,而非类。因为我们是针对对象进行存取与传输的,而非类,当我们需要重新获取之前的对象的时候,是直接读取出来的(从文件或网络中),而非根据类new出一个对象,这点是需要注意的。
2.如何序列化
序列话的方式有两种,一种是实现Serializable接口,一种是实现Parceable接口,下面会具体介绍这两种方式。
a.实现Serializable接口
这种序列化方式是Java提供的,它的优点是简单,其实Serializable接口是个空接口,因而我们并不需要实现什么抽象方法,但是我们却往往需要在类中声明一个静态变量标识(serialVersionUID),但这不是必须的,我们不声明,依然可以实现序列化,但是这样的话会对反序列化产生一定的影响,可能会在我们对类做了修改之后而造成对象的反序列化失败。声明方式如下:
- private static final long serialVersionUID = 8711368828010083044L;
注意,这里的值可以是任意值。
下面我们来具体实现下。
- package com.qc.admin.myserializableparceabledemo;
- import java.io.Serializable;
- /**
- * Created by admin on 2016/12/1.
- */
- public class User implements Serializable {
- private static final long serialVersionUID = 519067123721295773L;
- public int userId;
- public String userName;
- public boolean isMale;
- public User(int userId, String userName, boolean isMale) {
- this.userId = userId;
- this.userName = userName;
- this.isMale = isMale;
- }
- @Override
- public String toString() {
- return "User{ " +
- "userId = " + userId +
- ", userName = " + userName +
- ", isMale = " + isMale +
- " }";
- }
- }
下面是序列化与反序列化过程:
- private void beginSerizable() throws IOException, ClassNotFoundException {
- // 序列化
- User user = new User(2016, "qian", true);
- ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(getFilesDir(), "myfile.txt")));
- out.writeObject(user);
- out.close();
- // 反序列化
- // 注意,这里后面的“/myfile.txt”前面有个斜杠“/”,否则会报“FileNotFoundException”异常
- ObjectInputStream in = new ObjectInputStream(new FileInputStream(getFilesDir() + "/myfile.txt"));
- User mUser = (User) in.readObject();
- textView.setText(mUser.toString());
- in.close();
- Log.i("test",mUser.toString());
- }
运行结果截图:
注意:如果是在Android项目中调用以上方法,别忘了在Manifest.xml文件中配置如下权限:
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
b.实现Parceable接口
这种方式是Android提供的方式,相比较前面那种方式来讲,这种方式稍微有点复杂,我们需要自己尽享序列化与反序列化的操作,但是它却更加高效,并不需要执行大量的I/O操作。而且这种方式也是Android推荐的序列化方式,因此我们应该首选Parceable。只要实现了这个接口,一个类的对象就可以实现序列化并可以通过Intent和Binder进行传递了。下面请看实例:
- public class Book implements Parcelable {
- public String bookTitle;
- public int bookId;
- protected Book(Parcel in) {
- bookTitle = in.readString();
- bookId = in.readInt();
- }
- public static final Creator<Book> CREATOR = new Creator<Book>() {
- @Override
- public Book createFromParcel(Parcel in) {
- return new Book(in);
- }
- @Override
- public Book[] newArray(int size) {
- return new Book[size];
- }
- };
- @Override
- public int describeContents() {
- return 0;
- }
- @Override
- public void writeToParcel(Parcel parcel, int i) {
- parcel.writeString(bookTitle);
- parcel.writeInt(bookId);
- }
- }
这里将Book这个类就实现了Parcelable接口,其实在Android Studio IDE中,上述过程很简单,我们只需要定义一个类,实现Parcelable接口,然后在里面定义我们的属性或者说是字段,根据提示的错误,按照它提示的方法覆盖相应的方法,之后的一切其实都可以自动生成(不过如果需要构造方法的话,那就需要自动生成了,toString()方法也是自己实现的),所以不用担心在Android开发中通过实现Parceable接口会比较麻烦,因为AS都会为你自动生成。上面我们已经完整的将Book类实现了Parceable接口,那接下来如何序列化和反序列化呢?如果你说,刚才不是已经说过了吗,采用文件读取的方式不久可以了啦...当你那样做的时候,你会发现会报如下的错误:
Why???...什么情况?提示我们Book类没有实现序列化:
- /System.err: java.io.NotSerializableException: com.qc.admin.myserializableparceabledemo.Book
好啦,之所以出现这种问题,并不是我们的实现过程有问题,而是使用该类的方式行不通。到这里我们就明白了Serializable和Parceable两种方式实现序列化还是有区别的,刚才我们也讲了,Parceable更加高效,不会像Serializable那样有大量的I/O操作,这句话的具体含义就道出了Serializable与Parcelable区别:虽然两者都是用于支持序列化、反序列化话操作,但是两者最大的区别在于存储媒介的不同,Serializable是将序列化后的对象存储在硬盘上,使用I/O读写的方式,而Parcelable是将其存储在内存中,是针对内存的读写,熟悉计算机组成原理的朋友都知道,内存的读写速度显然要远远大于I/O的读写速度,这也是为什么Android中推荐使用Parcelable这种方式来实现对象的序列化。
那我们应该怎么使用通过实现Parcelable接口实现序列化的对象呢?答案是:通过Intent方式传递,除了基本类型外,Intent只能传输序列化之后的对象,对应这两种序列化方式,也有两种相应的方法:
- mIntent.getSerializableExtra(string name );
- mIntent.getParcelableExtra(String name );
当然,放入的操作就没有这种区分了,都是方法:
- mIntent.putExtra();
我们可以在第一个Activity中将序列化对象放入Intent,在另一个Activity中取出,比如:在另一端获取对象,例如:
- Bundle mBundle = getIntent().getExtras();
- Book mBook = mBundle.getParcelable("book1");
下面再看类User实现Parceable接口的过程,它内部包含了一个可序列化的类Book,具体细节跟上面的有点不同:
- package com.qc.admin.myserializableparceabledemo;
- import android.os.Parcel;
- import android.os.Parcelable;
- /**
- * Created by admin on 2016/12/1.
- */
- 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, Book book) {
- this.userId = userId;
- this.userName = userName;
- this.isMale = isMale;
- this.book = book;
- }
- protected User(Parcel in) {
- userId = in.readInt();
- userName = in.readString();
- isMale = in.readByte() != 0;
- // 此为不同之处1
- // 也可以通过这种方式:book = in.readParcelable(Thread.currentThread().getContextClassLoader());
- book = in.readParcelable(Book.class.getClassLoader());
- }
- 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];
- }
- };
- // 几乎在所有的情况下都应该返回0,只有在当前对象中存在文件描述的时候,此方法返回CONTENTS_FILE_DESCRIPTOR(常量值为1)
- @Override
- public int describeContents() {
- return 0;
- }
- // 将对象写入序列化结构中,其中i标识有两种值,0或者1(PARCELABLE_WRITE_RETURN_VALUE)
- // 为1时表示当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0
- @Override
- public void writeToParcel(Parcel parcel, int i) {
- parcel.writeInt(userId);
- parcel.writeString(userName);
- // 注意这里,并不是直接写入boolean值,而是写入整数值
- parcel.writeByte((byte) (isMale ? 1 : 0));
- // 此为不同之处2
- parcel.writeParcelable(book, i);
- }
- @Override
- public String toString() {
- return "User{ " +
- "userId = " + userId +
- ", userName = " + userName +
- ", isMale = " + isMale +
- "book = " + book.toString() +
- " }";
- }
- }
可以看出,结果已经正确的打印了出来了:
注意:在 Parcelable 中,我们无法直接写入 boolean 值,而是将其转化为整数值进行保存,这里为 Byte,当然,你也可以使用 Int 等。
对象的序列化存储:Serializable 和 Parceable的更多相关文章
- JAVA之旅(三十)——打印流PrintWriter,合并流,切割文件并且合并,对象的序列化Serializable,管道流,RandomAccessFile,IO其他类,字符编码
JAVA之旅(三十)--打印流PrintWriter,合并流,切割文件并且合并,对象的序列化Serializable,管道流,RandomAccessFile,IO其他类,字符编码 三十篇了,又是一个 ...
- Java基础学习总结——Java对象的序列化和反序列化
一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存 ...
- IO(四)----对象的序列化
对象的序列化: 将内存中的对象直接写入到文件设备中. 对象的反序列化: 将文件设备中持久化的数据转换为内存对象. 自定义类只要实现了Serializable接口,便可以通过对象输入输出流对对象进行 ...
- 黑马程序员_Java基础:序列化(Serializable)与反序列化
------- android培训.java培训.期待与您交流! ---------- 在学习IO中的ObjectOutputStream和ObjectInputStream时,会涉及到序列化和反序列 ...
- java io系列06之 序列化总结(Serializable 和 Externalizable)
本章,我们对序列化进行深入的学习和探讨.学习内容,包括序列化的作用.用途.用法,以及对实现序列化的2种方式Serializable和Externalizable的深入研究. 转载请注明出处:http: ...
- Java对象的序列化与反序列化
序列化与反序列化 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.一般将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等.在网络传输过程中,可以是字节或是 ...
- Java对象的序列化和反序列化[转]
Java基础学习总结--Java对象的序列化和反序列化 一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化.把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用 ...
- asp.net中对象的序列化,方便网络传输
对象序列化 是将对象状态转换为可保持或传输的格式的过程.反序列化 是将流转换为对象序列化和反序列化相结合 可以使对象数据轻松的存储和传递 在 .NET 中,如果是对象可序列化,需要在 声明对象的开始部 ...
- Java:对象的序列化
一.对象序列化机制 序列化机制允许将实现序列化的Java对象转换为字节序列,这些字节序列可以被保存在磁盘上或通过网络传输,以备以后重新恢复原来的对象: 序列化机制使得对象可以脱离程序的运行而独立存在: ...
随机推荐
- ORACEL 创建表空间
注意点: 1.如果在PL/SQL 等工具里打开的话,直接修改下面的代码中[斜体加粗部分]执行 2.确保路径存在,比如[D:\oracle\oradata\Oracle9i\]也就是你要保存文件的路径存 ...
- Petuum - Careers
Petuum - Careers Cloudformation
- Django Pagination
Django provides a few classes that help you manage paginated data – that is, data that’s split acros ...
- Supported_Hardware#4G_LTE_cards_and_modems
https://wiki.mikrotik.com/wiki/Supported_Hardware#4G_LTE_cards_and_modems
- mount umont
如果想在运行的Linux下访问其它文件系统中的资源的话,就要用mount命令来实现. 2. mount的基本用法是?格式:mount [-参数] [设备名称] [挂载点] 其中常用的参数有: ...
- .Net线程问题解答
基础篇 怎样创建一个线程 受托管的线程与 Windows线程 前台线程与后台线程 名为BeginXXX和EndXXX的方法是做什么用的 异步和多线程有什么关联 WinForm多线程编程篇 我的多线程W ...
- Python学习(三)流程控制
Python流程控制 本章介绍 python 的基础流程控制.包括 if 条件语句.for 循环 和 while 循环语句: continue 及 break 的用法等. 基本用法与 C 和 Java ...
- JavaScript 中 Object ,Prototype 相关的属性和方法
span { font-family: 'Consolas'; font-size: 10pt; color: #ffffff; } .sc0 { } .sc2 { color: #c0c0c0; } ...
- XML 简单介绍
先附上一张XML 大概图:详解见博客内容. 一.定义 XML(EXtensible Markup Language) :可扩展标记语言. 设计的用途:用来描述,存储,传输数据信息. 二.特色 1.单纯 ...
- http://blog.csdn.net/steveguoshao/article/details/38414145
http://blog.csdn.net/steveguoshao/article/details/38414145