序列化和反序列化的4个问题


**写在前面**


上一篇文章,我们介绍了几个入门级别的序列化的问题,但是,当你了解了这些,还是会有很多新的问题在等着你,今天我们继续开始序列化和反序列化的征程。看看如下几个问题,能回答上来多少?

先看问题

1.控制序列化过程时,有一个特定的子对象不愿让Java的序列化机制自动保存与恢复。比如说密码。这个时候该怎么做?

2.序列化机制保存的是什么信息,类中的方法会被保存吗?

3.声明为static和transient类型的成员数据可以被序列化吗?

4.谈谈对serialVersionUID的理解?

对特定的子对象不采取序列化

先来看第一个问题:密码我们肯定不想被序列化。接着

为防止对象的敏感部分被序列化,


一个办法是将自己的类实现为Externalizable,这样一来,没有任何东西可以自动序列化,只能在 writeExternal() 明确序列化那些需要的部分。

代码为证

User.java

image.png


Test1.java

image.png

已经看不到密码了。


然而,若操作的是一个 Serializable 对象,所有序列化操作都会自动进行。为解决这个问题,可以用transient(临时)逐个字段地关闭序列化。

代码为证

User1.java

image.png

Test1.java

image.png

序列化保存的是什么信息

看看Java都对User1类序列化了哪些信息,为了便于观察使用Linux下面的strings函数

image.png

这些信息很直观的告诉我们序列化都保存了些什么内容:

1)对象的类型

2)对象属性的类型

3)对象属性的值


继续验证:在User1.java中添加2个方法:

image.png

查看序列化的信息:

image.png

没有变化。

序列化机制只保存对象的类型信息,属性的类型信息和属性值,和方法没有什么关系,无论你给这个类增加多少个方法,序列化内容也不会增加任何东西

声明为static和transient类型的成员数据可以被序列化吗?

1.用transient逐个字段地关闭序列化。也就是一个类的属性被transient修饰,就不会被序列化。上面的代码已经验证。

代码验证static修饰的成员数据

User1.java

image.png

Test1.java

image.png

有人会说了,被static修饰的属性也是可以序列化。但是现实无情的欺骗了我们。


真相如下:

静态成员属于类级别的,所以不能序列化,序列化只是序列化了对象而已,这里“不能序列化”的意思是序列化信息中不包含这个静态成员域,下面之所以password输出还是yunxiao,是因为测试都在同一个机器(而且是同一个进程),因为这个jvm已经把password加载进来了,所以获取的是加载好的password,如果是传到另一台机器或者关掉程序重新写个程序读入object5.txt,此时因为别的机器或新的进程是重新加载password的,所以password信息就是初始时的信息,即null。所以,总结来看,静态成员是不能被序列化的,所以正确的运行结果应该是:

image.png


验证一下:序列化的代码注释。

image.png


或通过Linux中的strings查看:

image.png


静态成员是不能被序列化的,因为静态成员是随着类的加载而加载的,与类共存亡。

谈谈对serialVersionUID的理解

serialVersionUID是叫做流的唯一标识符,通常也被称为序列版本UID。每个可以序列化的类都有一个唯一标识号与它相关联。

如果你没有在一个位为serialVersionUID的私有静态final的long域中显示的指定该标识号。系统就会自动地根据这个类来调用一个复杂的计算过程,从而在运行时产生该标识符。这个自动产生的值会受到类名称、它所实现的接口名称、以及所有公有的和受保护的成员的名称所影响。如果你通过任何方法改变了这些信息,比如,增加了一个不是很重要的工具方法,自动产生的序列版本UUID也会发生变化。因此,如果你没有申明一个显示的序列版本UUID,兼容性将会遭到破坏。


欢迎加入51码农网,让我们一起组队学习编程,每日打卡,一天进步一点点。www.51manong.com

关注公众号:51码农网

51码农公众平台.jpg












猜你喜欢

转载自blog.csdn.net/yunxiaoxiehou/article/details/86551814