一、关键知识点
1、transient用于变量上,不能用于方法或类上。
2、被transient修饰过的变量将不会被序列化,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。即对象只能存在于内存中,无法进行网络传输或保存到本地。
3、静态变量无论有没有transient修饰,都不会被序列化。
二、详解
transient是Java中不太常用的关键字,主要用于序列化的操作上,正常情况下,当我们需要将一个对象进行序列化(主要是Serializable接口)时,该对象中的所有变量都将被序列化,把其状态保存为一组字节,然后通过反序列化将字节信息转化为我们所需要的对象。关于Java序列化的知识,参考:https://www.hollischuang.com/archives/1140
那有一些数据如果不想被序列化的时候,控制不想被序列化的数据,就要用到transient了,为什么会有这种需求?举个例子:
ArrayList的源码中就使用了transient字段:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
transient Object[] elementData; // non-private to simplify nested class access
private int size;
}
笔者省略了其他成员变量,从上面的代码中可以知道ArrayList实现了java.io.Serializable
接口,那么我们就可以对它进行序列化及反序列化。因为elementData是transient
的,所以我们认为这个成员变量不会被序列化而保留下来。
了解ArrayList的人都知道, ArrayList实际上是动态数组,每次在放满以后自动增长设定的长度值,如果数组自动增长长度设为100,而实际只放了一个元素,那就会序列化99个null元素。为了保证在序列化的时候不会将这么多null同时进行序列化,ArrayList把元素数组设置为transient。然后结合Serializable的writeObject
和readObject方法
把其中的元素保留下来,实现持久化,主要还是为了减少内存占用,提高运算速率。
通过transient,我们可以更好的控制我们的数据:
1、将有些不必要的数据,不进行序列化,从而减少内存占用或网络资源;
2、牵涉到敏感信息如用户密码等数据时,可以通过transient将这些数据只保留在内存中,更安全;