transient 关键字

本贴最后更新于 1743 天前,其中的信息可能已经时移世异

一、什么是 transient

简而言之,被 transient 标记的变量在序列化时会被忽略,当然没有序列化就没有反序列化

看看下面的例子来加深理解:

@Data
class Employee implements Serializable
{
   private String           firstName;
   private String           lastName;
   private transient String password;
}
//序列化对象
try
{
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.txt"));
    Employee emp = new Employee();
    emp.setFirstName("john");
    emp.setLastName("jack");
    emp.setPassword("password");
    oos.writeObject(emp);
    oos.close();
} catch (Exception e)
{
    System.out.println(e);
}
// 反序列化
try
{
    ObjectInputStream ooi = new ObjectInputStream(new FileInputStream("test.txt"));
    Employee readEmpInfo = (Employee) ooi.readObject();
    System.out.println(readEmpInfo.getFirstName());
    System.out.println(readEmpInfo.getLastName());
    System.out.println(readEmpInfo.getPassword());
    // john
    // jack
    // null
    ooi.close();
} catch (Exception e)
{
    System.out.println(e);
}

可以看到被 transient 修饰的属性反序列化为 null。

二、transient 应用场景

  1. 对象的某个属性的值,需要根据其他属性来计算的时候,应该把这个属性加上 transient

这种属性应该是每次都用程序计算,而不是用序列化来持久化。比如说基于时间戳的值,像年龄,或者需要保存一段时间,这段时间是某个时间戳和当前时间戳的时间段。这种情况就不应该将这种属性值序列化。

  1. 涉及隐私以及安全问题的属性不应该序列化。
  2. 本身就没有实现序列化接口的属性,如果被序列化会抛出 NotSerializableException 异常。
  3. 逻辑道理上不需要序列化。比如说类里面有个 Logger 对象,但是 Logger 只是用来写日志,不需要保留这个对象的状态。再比如线程对象,线程对象保留是某个时间点的线程状态,没有持久化的意义。

三、transientfinal 组合

一个属性同时被 transientfinal 修饰,如果这个属性属于基本数据类型和 String,那么序列化的时候 transient 会被会忽略掉。因为会被 JVM 认为是常量。

其他引用类型(包括基本数据类型的包装类),即使被 final 修饰,transient 也会生效

四、实际应用举例--HashMap

// HashMap中使用 transient标记的字段
transient Entry           table[];
transient int             size;
transient int             modCount;
transient int             hashSeed;
private transient Set     entrySet;

可以看出 HashMap 的 key-value 相关的存储都是用 transient 修饰的,也就是说序列化的时候不会被序列化。

private void readObject(java.io.ObjectInputStream s)
    throws IOException, ClassNotFoundException {
    // Read in the threshold (ignored), loadfactor, and any hidden stuff
    s.defaultReadObject();
    reinitialize();
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new InvalidObjectException("Illegal load factor: " +
                                         loadFactor);
    s.readInt();                // Read and ignore number of buckets
    int mappings = s.readInt(); // Read number of mappings (size)
    if (mappings < 0)
        throw new InvalidObjectException("Illegal mappings count: " +
                                         mappings);
    else if (mappings > 0) { // (if zero, use defaults)
        // Size the table using given load factor only if within
        // range of 0.25...4.0
        float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
        float fc = (float)mappings / lf + 1.0f;
        int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
                   DEFAULT_INITIAL_CAPACITY :
                   (fc >= MAXIMUM_CAPACITY) ?
                   MAXIMUM_CAPACITY :
                   tableSizeFor((int)fc));
        float ft = (float)cap * lf;
        threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
                     (int)ft : Integer.MAX_VALUE);

        // Check Map.Entry[].class since it's the nearest public type to
        // what we're actually creating.
        SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);
        @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
        table = tab;

        // Read the keys and values, and put the mappings in the HashMap
        for (int i = 0; i < mappings; i++) {
            @SuppressWarnings("unchecked")
            K key = (K) s.readObject();
            @SuppressWarnings("unchecked")
            V value = (V) s.readObject();
            putVal(hash(key), key, value, false, false);
        }
    }
}

HashMap 反序列化后,会重新 hash 计算把 key-value 存进去。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3190 引用 • 8214 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...