对象的序列化存储: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对象转换为字节序列,这些字节序列可以被保存在磁盘上或通过网络传输,以备以后重新恢复原来的对象: 序列化机制使得对象可以脱离程序的运行而独立存在: ...
随机推荐
- MSChart使用小结
在用到图表展示某项.多项信息的统计情况,很正常联想到MSChart控件. 以VS2008开发为例,在工具箱也中右击,选择”choose items“,打开对话框,选择COM组件T ...
- linuxmint - setup - 搜狗输入法
安装好linuxmint18后,官网下载搜狗输入法安装包安装.安装成功后,发现缺失部分界面,包括输入候选框,软件设置,fcitx设置都不太正常. 解决: 安装:fcitx-ui-classic 另: ...
- JLink Support for the Nuvoton NUC1xx devices
http://forum.segger.com/index.php?page=Thread&threadID=1441 Friday, April 19th 2013, 7:25pm Hi M ...
- 利用AWR 查看SQL 执行计划
在AWR中定位到问题SQL语句后想要了解该SQL statement的具体执行计划,于是就用AWR报告中得到的SQL ID去V$SQL等几个动态性能视图中查询,但发现V$SQL或V$SQL_PLAN视 ...
- 【spring cloud】子模块module -->导入一个新的spring boot项目作为spring cloud的一个子模块微服务,怎么做/或者 每次导入一个新的spring boot项目,IDEA不识别子module,启动类无法启动/右下角没有蓝色图标
如题:导入一个新的spring boot项目作为spring cloud的一个子模块微服务,怎么做 或者说每次导入一个新的spring boot项目,IDEA不识别,启动类无法启动,怎么解决 下面分别 ...
- Orchard运用 - 如何隐藏去除某些Meta标记
众所周知,每个系统多多少少都会有一些痕迹或标记之类的东西, 比如默认的Orchard搭建的网站, 如果你查看源代码即可看到类似的代码: <meta content="Orchard&q ...
- 【属性动画示例】Property Animation
MainActivity 属性动画常用操作 // 可操控的属性有:alpha:x/y:scaleX/scaleY:rotation/rotationX/rotationY:transitionX/tr ...
- Ubuntu下如何安装与运行Redis
内容中包含 base64string 图片造成字符过多,拒绝显示
- Kubenertes资源分配之Request和Limit解析
收录待用,修改转载已取得腾讯云授权 Kubernetes是一个容器集群管理平台,Kubernetes需要统计整体平台的资源使用情况,合理地将资源分配给容器使用,并且要保证容器生命周期内有足够的资源来保 ...
- .NET-MVC站点部署到windows server2008r2服务器404错误
iis站点搭建 产生原因: 由于服务器上的.net4.0没有进行注册导致的 解决方法: 注册.net 4.0 打开运行-cmd-输入如下命令: C:\WINDOWS\Microsoft.NET\Fra ...