transient关键字在java中就是用来表明一个字段不被序列化的意思。
比如,你有一个字段是派生出来的,也就是通过其他字段计算出来的,只是为了在业务逻辑中方便使用而已。而不是在序列化的时候持久化他的状态。
下面我们就看一例子,这里例子里边有个图片对象,同时有个缩略图对象:
class GalleryImage implements Serializable
{
private Image image;
private transient Image thumbnailImage;
private void generateThumbnail()
{
// Generate thumbnail.
}
private void readObject(ObjectInputStream inputStream)
throws IOException, ClassNotFoundException
{
inputStream.defaultReadObject();
generateThumbnail();
}
}
在上面这个例子中,thumbnailImage是一个缩略图,这个缩略图是调用generateThumbnail方法生成的。
这个thumbnailImage字段被标记为transient,所以只有那个image会被序列化,thumbnailImage就不会被序列化了。这样的话,需要保存序列化对象的时候 存的东西也更少一点。
那么在实际的开发中哪些变量应该被mark为transient呢?
这里可以给你提供一个基本的规则,就是那些经过其他字段运算或处理就能得出的变量就适合做成transient变量。比如你有一个字段叫“interest”,这个字段的值是其他的字段处理后的结果。比如有principle, rate, time等等。这个时候就没必要去序列化这个interest。还有比如有个字段叫sum,这个求和的值可能是一个list字段通过循环计算得出的,这个sum就不需要进行序列化,你就可以mark为transient。还有比如说一篇文章,同时有个count字段。那么这个count也是通过article的内容的来计算出来的,那么这个count你也可以mark为transient。还有一个典型的用法就是Logger。这个logger属性相信大家都不会陌生,就是我们声明的日志字段,这个属性显然不用被序列化,这个时候你就可以把logger mark为transient。
下面这个图简单展示了transient的字段和static 字段在序列化过程中的前后结果:
你会发现static的值也过去了。其实这个值不是被序列化过去的。而是因为它本身就是类的变量而已。
相信你现在已经了解了transient的基本用法。那么我们就继续深入一下,你可能注意到前面的代码中有下面这么一段代码:
private void readObject(ObjectInputStream inputStream)
throws IOException, ClassNotFoundException
{
inputStream.defaultReadObject();
generateThumbnail();
}
这个是做什么的呢?由于上面的thumbnailImage(缩略图)是不希望被序列化的,但我们又希望调用者能够拿到,于是我们就可以通过在readObject方法中来进行生成缩略图。而这个缩略图并没有在序列化文件中出现。
在反序列化的时候,readObject方法就会被调用来执行一些定制化的操作使得对象的状态回到当初序列化的状态。这里的缩略图(thumbnail)就是需要被生成的,所以readObject就被重写掉了(这里你可以认为是重写),这样的话,就在反序列化的过程中动态的生成了缩略图。
下面我们上一段代码更好的展现一下上面说的readObject以及相应的writeObject:
序列化类:
demo代码:
运行结果:
你会发现年龄也被读取到了。
现在我们再来看看序列化文件中的obj.txt中的内容:
你会发现txt中并没有age。
这就是我们通过writeObject和readObject做到的。
本文分享自 ImportSource 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!