Serializable

  • 静态变量序列化不会被保存
public class Test implements Serializable {

    private static final long serialVersionUID = 1L;

    public static int staticVar = 5;

    public static void main(String[] args) {
try {
//初始时staticVar为5
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("result.obj"));
out.writeObject(new Test());
out.close(); //序列化后修改为10
Test.staticVar = 10; ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
"result.obj"));
Test t = (Test) oin.readObject();
oin.close(); //再读取,通过t.staticVar打印新的值
System.out.println(t.staticVar); } catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

最后的输出是 10

  • 父类的序列化与 Transient 关键字

一个子类实现了 Serializable 接口,它的父类都没有实现 Serializable 接口,序列化该子类对象,然后反序列化后输出父类定义的某变量的数值,该变量数值与序列化时的数值不同。

要想将父类对象也序列化,就需要让父类也实现Serializable 接口。如果父类不实现的话的,就 需要有默认的无参的构造函数。如果你考虑到这种序列化的情况,在父类无参构造函数中对变量进行初始化,否则的话,父类变量值都是默认声明的值,如 int 型的默认是 0,string 型的默认是 null。

我们熟悉使用 Transient 关键字可以使得字段不被序列化,那么还有别的方法吗?根据父类对象序列化的规则,我们可以将不需要被序列化的字段抽取出来放到父类中,子类实现 Serializable 接口,父类不实现,根据父类序列化规则,父类的字段数据将不被序列化。

  • 序列化存储规则
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("result.obj"));
Test test = new Test();
//试图将对象两次写入文件
out.writeObject(test);
out.flush();
System.out.println(new File("result.obj").length());
out.writeObject(test);
out.close();
System.out.println(new File("result.obj").length()); ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
"result.obj"));
//从文件依次读出两个文件
Test t1 = (Test) oin.readObject();
Test t2 = (Test) oin.readObject();
oin.close(); //判断两个引用是否指向同一个对象
System.out.println(t1 == t2);

对同一对象两次写入文件,打印出写入一次对象后的存储大小和写入两次后的存储大小,然后从文件中反序列化出两个对象,比较这两个对象是否为同一对象。一般的思维是,两次写入对象,文件大小会变为两倍的大小,反序列化时,由于从文件读取,生成了两个对象,判断相等时应该是输入 false 才对,但是。。。

我们看到,第二次写入对象时文件只增加了 5 字节,并且两个对象是相等的。。Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,上面增加的 5 字节的存储空间就是新增引用和一些控制信息的空间。反序列化时,恢复引用关系,使得代码中的 t1 和 t2 指向唯一的对象,二者相等,输出 true。该存储规则极大的节省了存储空间。

Parcelable

android.os.BadParcelableException: ClassNotFoundException when unmarshalling

public Config config;
public RowView(Parcel in){
type = in.readString();
interfaceUrl = in.readString();
size = in.readInt();
config = in.readParcelable(null);
}

报错的语句即为config = in.readParcelable(null);

  • 分析

根据android文档介绍:

readParcelable (ClassLoader loader)

loader A ClassLoader from which to instantiate the Parcelable object, or null for the default class loader.即loader为空时系统会采取默认的class loader。

Android有两种不同的classloaders:framework classloader和apk classloader,其中framework classloader知道怎么加载android classes,apk classloader知道怎么加载you code,apk classloader继承自framework classloader,所以也知道怎么加载android classes。

在应用刚启动时,默认class loader是apk classloader,但在系统内存不足应用被系统回收会再次启动,这个默认class loader会变为framework classloader了,所以对于自己的类会报ClassNotFoundException。

  • 解决

将config = in.readParcelable(null);改为config = in.readParcelable(Config.class.getClassLoader());

Config.class.getClassLoader()即为apk classloader, 其中Config.class可以改为你程序中自己写的任意类,因为他们同样指向apk loader。

试着改为config = in.readParcelable(Activity.class.getClassLoader());你会发现依然ClassNotFoundException因为Activity.class.getClassLoader()指向的是framework classloader

我是天王盖地虎的分割线

参考:http://www.ibm.com/developerworks/cn/java/j-lo-serial/index.html

Android -- Serializable和Parcelable需要注意的的更多相关文章

  1. android Serializable 和 Parcelable 区别

      android 中自定义的对象序列化的问题有两个选择一个是Parcelable,另外一个是Serializable. 一 序列化原因: 1.永久性保存对象,保存对象的字节序列到本地文件中:2.通过 ...

  2. Android序列化之Serializable和Parcelable

    PS:还有几天就开学了.先来一发. 学习内容: 1.序列化的目的 2.Android中序列化的两种方式 3.Parcelable与Serializable的性能比较 4.Android中如何使用Par ...

  3. 浅谈Android中Serializable和Parcelable使用区别

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.概述 Android开发的时候,我们时长遇到传递对象的需求,但是我们无法将对象的引用传给Activity或者Fragment,我们需要将这些对象 ...

  4. Android中Serializable和Parcelable序列化对象详解

    学习内容: 1.序列化的目的 2.Android中序列化的两种方式 3.Parcelable与Serializable的性能比较 4.Android中如何使用Parcelable进行序列化操作 5.P ...

  5. Android序列化:Parcelable/Serializable

    1.易用性及速度 1.1 Serializable——简单易用 Serializable的作用是为了保存对象的属性到本地文件.数据库.网络流.rmi以方便数据传输,当然这种传输可以是程序内的也可以是两 ...

  6. android序列化(1)Parcelable与Serializable

    1.Android中实现序列化有两个选择 一是实现Serializable接口(是JavaSE本身就支持的),实现Serializable接口非常简单. 一是实现Parcelable接口(是Andro ...

  7. Serializable 和 Parcelable 区别

    http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0204/2410.html http://www.cnblogs.com/blu ...

  8. android对象序列化Parcelable浅析

    一.android序列化简介 我们已经知道在Android使用Intent/Bindler进行IPC传输数据时,需要将对象进行序列化. JAVA原本已经提供了Serializable接口来实现序列化, ...

  9. 序列化Serializable和Parcelable

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 简单记录下序列化Serializable和Parcelable的使用方法. Android中Intent如果要传递类对象,可以通过两 ...

随机推荐

  1. c# 实现获取汉字十六进制Unicode编码字符串

    1.  汉字转十六进制UNICODE编码字符串 /// <summary>        /// ////        /// </summary>        /// & ...

  2. Bootstrap入门学习(三)——简单项目

    此样例来自Bootstrap官网提供的入门级模版.仅仅有主要的东西:引入了预编译版的 CSS 和 JavaScript 文件,页面仅仅包括了一个 container 元素. 引入Bootstrap 创 ...

  3. How to properly set clock speed for STM32F4xx devices

    http://stm32f4-discovery.com/2015/01/properly-set-clock-speed-stm32f4xx-devices/ I see that you have ...

  4. Linux 下smi/mdio总线通信

    Linux 下smi/mdio总线通信 韩大卫@吉林师范大学 下面代码描述了在用户层访问smi/mdio总线, 读写phy芯片寄存器的通用代码.Linux内核2.6以上通用. 将下面代码编译后,将可执 ...

  5. bash 脚本中分号的作用

    在Linux bash shell中,语句中的分号一般用作代码块标识 1.单行语句一般要用到分号来区分代码块.比如: weblogic@pmtest:/$if [ "$PS1" ] ...

  6. SystemParametersinfo的用法(一)

    SystemParametersinfo的用法(一) 函数功能:该函数查询或设置系统级参数.该函数也可以在设置参数中更新用户配置文件. 函数原型:B00L SystemParametersinfo(U ...

  7. Sqlite3+EF6踩的坑

    摘要 最近在用winform,有些数据需要本地存储,所以想到了使用sqlite这个文件数据库.在使用Nuget安装sqlite的时候,发现会将Ef也安装上了,所以想着使用EF进行数据的操作吧,所以这就 ...

  8. 让AngularJS的controllers之间共享数据

    如何让controller之间共享数据呢?大致是让不同controller中的变量指向同一个实例. 通过service创建一个存放共享数据的对象. .service("greeting&qu ...

  9. 线程、线程ID获取

    一.进程ID获取 1.1  当前进程的Id 方法1 通过进程名获取 下面的例子中,也包含了获取该进程下的线程的方法. System.Diagnostics.Process[] processes:bo ...

  10. 线程中sleep方法和wait方法有什么区别?(转)

    本文转自https://www.cnblogs.com/linkstar/p/6043846.html 线程中sleep方法和wait方法有什么区别?   如果你没有接触过java的多线程,那么多对于 ...