Java关键字transient

互联网架构师

共 9400字,需浏览 19分钟

 ·

2021-08-23 16:12

上一篇:深夜看了张一鸣的微博,让我越想越后怕

作者:小丸子的呆地
链接:https://www.jianshu.com/p/db184d3acff8

用transient声明一个实例变量,当对象存储时,它的值不需要维持。

作用

Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。

验证

package com.qjk;
import java.io.*;
public class TestTransient {

    static class User implements Serializable {
        String name;
        int age;
        transient int transient_age;
        String sex;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        User user = new User();
        user.age = 12;
        user.transient_age = 12;
        user.name = "小丸子";
        user.sex = "nv";

        System.out.println("age:" + user.age);
        System.out.println("transient_age:" + user.transient_age);
        System.out.println("name:" + user.name);
        System.out.println("sex:" + user.sex);

        System.out.println("----------------序列化+反序列化----------------");

        // 序列化后写入缓存
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(user);
        oos.flush();
        oos.close();

        byte[] buf = baos.toByteArray();
        // 从缓存中读取并执行反序列化
        ByteArrayInputStream bais = new ByteArrayInputStream(buf);
        ObjectInputStream ois = new ObjectInputStream(bais);

        User u = (User) ois.readObject();

        System.out.println("age:" + u.age);
        System.out.println("transient_age:" + u.transient_age);
        System.out.println("name:" + u.name);
        System.out.println("sex:" + u.sex);

    }
}

结果输出

age:12
transient_age:12
name:小丸子
sex:nv
----------------序列化+反序列化----------------
age:12
transient_age:0
name:小丸子
sex:nv


扩展

Exteranlizable

Java序列化提供两种方式。一种是实现Serializable接口。另一种是实现Exteranlizable接口。Externalizable接口是继承于Serializable ,需要重写writeExternal和readExternal方法,它的效率比Serializable高一些,并且可以决定哪些属性需要序列化(即使是transient修饰的),但是对大量对象,或者重复对象,则效率低。

ArrayList中的transient

下面是ArrayList中的一段代码

    /**
     * ArrayList 的元素存储在其中的数组缓冲区。ArrayList 的容量就是这个数组缓冲
     * 区的长度。添加第一个元素时,任何带有 elementData == 
     * DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList 都将扩展为 
     * DEFAULT_CAPACITY。
     */

    transient Object[] elementData; // non-private to simplify nested class access

ArrayList提供了自定义的wirteObject和readObject方法:

    /**
     * Save the state of the <tt>ArrayList</tt> instance to a stream (that
     * is, serialize it).
     *
     * @serialData The length of the array backing the <tt>ArrayList</tt>
     *             instance is emitted (int), followed by all of its elements
     *             (each an <tt>Object</tt>) in the proper order.
     */

    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException
{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    /**
     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
     * deserialize it).
     */

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException 
{
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

我理解这里定义elementData为transient是为了防止数据重复被写入磁盘,节省空间。

如果对象声明了readObject和writeObject方法,对象在被序列化的时候会执行对象的readObject和writeObject方法。

静态属性

静态属性,无论是否被transient修饰,都不会被序列化。

感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!小编到你上高速。

    · END ·
最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全


正文结束


推荐阅读 ↓↓↓

1.不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

2.如何才能成为优秀的架构师?

3.从零开始搭建创业公司后台技术栈

4.程序员一般可以从什么平台接私活?

5.37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

6.IntelliJ IDEA 2019.3 首个最新访问版本发布,新特性抢先看

7.这封“领导痛批95后下属”的邮件,句句扎心!

8.15张图看懂瞎忙和高效的区别!

一个人学习、工作很迷茫?


点击「阅读原文」加入我们的小圈子!

浏览 40
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报