【第22期】观点:IT 行业加班,到底有没有价值?

Serializable和Parcelable以及持久化

原创 2015年11月17日 15:40:15

1、什么是序列化和反序列化
Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。


2、什么情况下需要序列化 
a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;

3、如何实现序列化

将需要序列化的类实现Serializable接口就可以了,Serializable接口中没有任何方法,是一个标记,即表明这个类可以序列化。


4、序列化和反序列化例子

如果我们想要序列化一个对象,首先要创建某些OutputStream(如FileOutputStream、ByteArrayOutputStream等),然后将这些OutputStream封装在一个ObjectOutputStream中。这时候,只需要调用writeObject()方法就可以将对象序列化,并将其发送给OutputStream记住:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构。而反序列的过程(即将一个序列还原成为一个对象),需要将一个InputStream(如FileInputstream、ByteArrayInputStream等)封装在ObjectInputStream内,然后调用readObject()即可。




作用

Serializable的作用是为了保存对象的属性到本地文件、数据库、网络流、rmi以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而Android的Parcelable的设计初衷是因为Serializable效率过慢,为了在程序内不同组件间以及不同Android程序间(AIDL)高效的传输数据而设计,这些数据仅在内存中存在,Parcelable是通过IBinder通信的消息的载体。

从上面的设计上我们就可以看出优劣了。

 

2、效率及选择

Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如activity间传输数据,而Serializable可将数据持久化方便保存,所以在需要保存或网络传输数据时选择Serializable,因为android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化

 

3、编程实现

对于Serializable,类只需要实现Serializable接口,并提供一个序列化版本id(serialVersionUID)即可。而Parcelable则需要实现writeToParcel、describeContents函数以及静态的CREATOR变量,实际上就是将如何打包和解包的工作自己来定义,而序列化的这些操作完全由底层实现

package com.sheepmu;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class MyTest implements Serializable
{
	private static final long serialVersionUID = 1L;
	private String name="SheepMu";
	private int age=24;
	public static void main(String[] args)
	{//以下代码实现序列化
		try 
		{
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));//输出流保存的文件名为 my.out ;ObjectOutputStream能把Object输出成Byte流
			MyTest myTest=new MyTest();
			oos.writeObject(myTest); 
			oos.flush();  //缓冲流 
			oos.close(); //关闭流
		} catch (FileNotFoundException e) 
		{		 
			e.printStackTrace();
		} catch (IOException e) 
		{
			e.printStackTrace();
		} 
		fan();//调用下面的  反序列化  代码
	}
	public static void fan()//反序列的过程
	{	 
         ObjectInputStream oin = null;//局部变量必须要初始化
		try
		{
			oin = new ObjectInputStream(new FileInputStream("my.out"));
		} catch (FileNotFoundException e1)
		{		 
			e1.printStackTrace();
		} catch (IOException e1)
		{
			e1.printStackTrace();
		}      
        MyTest mts = null;
		try {
			mts = (MyTest ) oin.readObject();//由Object对象向下转型为MyTest对象
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}     
         System.out.println("name="+mts.name);    
         System.out.println("age="+mts.age);    
	}
}



Parcelable的一个实现例子如下

复制代码
public class MyParcelable implements Parcelable {
     private int mData;
     private String mStr;

     public int describeContents() {
         return 0;
     }

     // 写数据进行保存
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mData);
         out.writeString(mStr);
     }

     // 用来创建自定义的Parcelable的对象
     public static final Parcelable.Creator<MyParcelable> CREATOR
             = new Parcelable.Creator<MyParcelable>() {
         public MyParcelable createFromParcel(Parcel in) {
             return new MyParcelable(in);
         }

         public MyParcelable[] newArray(int size) {
             return new MyParcelable[size];
         }
     };
     
     // 读数据进行恢复
     private MyParcelable(Parcel in) {
         mData = in.readInt();
         mStr = in.readString();
     }
 }
复制代码

从上面我们可以看出Parcel的写入和读出顺序是一致的。如果元素是list读出时需要先new一个ArrayList传入,否则会报空指针异常。如下:

list = new ArrayList<String>();
in.readStringList(list);

 PS: 在自己使用时,read数据时误将前面int数据当作long读出,结果后面的顺序错乱,报如下异常,当类字段较多时务必保持写入和读取的类型及顺序一致

11-21 20:14:10.317: E/AndroidRuntime(21114): Caused by: java.lang.RuntimeException: Parcel android.os.Parcel@4126ed60: Unmarshalling unknown type code 3014773 at offset 164

 

4、高级功能上

Serializable序列化不保存静态变量,可以使用Transient关键字对部分字段不进行序列化,也可以覆盖writeObject、readObject方法以实现序列化过程自定义


5、序列化ID

序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。这也可能是造成序列化和反序列化失败的原因,因为不同的序列化id之间不能进行序列化和反序列化。


6.序列化前和序列化后的对象的关系

是 "=="还是equal? or  是浅复制还是深复制? 

答案:深复制,反序列化还原后的对象地址与原来的的地址不同

序列化前后对象的地址不同了,但是内容是一样的,而且对象中包含的引用也相同。换句话说,通过序列化操作,我们可以实现对任何可Serializable对象的”深度复制(deep copy)"——这意味着我们复制的是整个对象网,而不仅仅是基本对象及其引用。对于同一流的对象,他们的地址是相同,说明他们是同一个对象,但是与其他流的对象地址却不相同。也就说,只要将对象序列化到单一流中,就可以恢复出与我们写出时一样的对象网,而且只要在同一流中,对象都是同一个。



版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

下载管理器类的封装(观察者模式)

package com.study.googleplay.manager; import java.util.ArrayList; import java.util.List; /** * 下载...

Android远程数据库通信实现

由于学院需要提交一个学年论文,正好借此机会开始我的博客生活,我会在随后的日子在里不断更新博客。 内容摘要:随着移动互联网技术的的发展以及智能手持终端的普及,实现远程数据的通信成为了智能应用的关键。目...

程序员升职加薪指南!还缺一个“证”!

CSDN出品,立即查看!

android 三种网络通信接口及各个接口的代码示例

第一部分 Android网络基础    Android平台浏览器采用了WeBKit引擎,这款名为Chorme Lite的Web浏览器拥有强大扩展特性,每个开发者都以为编写自己的插件,使得浏览器的功能更...

Android网络通信篇:Socket TCP(简易聊天室)

简易界面 Android客户端登录 Android客户端登录后服务器和PC客户端界面 Android客户端和PC客户端聊天   注:在同一台PC机下测试,故所有的IP都一样了...

Android的网络与通信

第一部分 Android网络基础    Android平台浏览器采用了WeBKit引擎,这款名为Chorme Lite的Web浏览器拥有强大扩展特性,每个开发者都以为编写自己的插件,使得浏览...

Parcelable和Serializable的作用、效率、区别及选择

1、作用 Serializable的作用是为了保存对象的属性到本地文件、数据库、网络流、rmi以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而Android的Parcelable的...

Android使用HttpURLConnection获取数据

Activity的代码public class NetActivity extends Activity { private static final int MSG_UPDATE_TEXT = 1...

android 数据传递详解(Serialization、Parcelable、Parcel、Intent、Bundle)

[android] Serializable 和 Parcelable 区别 android 中自定义的对象序列化的问题有两个选择一个是Parcelable,另外一个是Serializable。 ...

Android系统中Parcelable和Serializable的区别

进行Android开发的时候,我们都知道不能将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递。 通过Android的...

android 中传递对象两种方法探索(Serializable,Parcelable)

相信大家在android开发的过程中总会遇到要在Activity中间传递数据的情况,当然,遇到需要在Intent中传递对象的情况也不可避免,所以我就so了一下相关的知识,在这里总结消化一下。就目前来说...
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)