• 关键字transient是干啥的


    百度百科的解释:

            Java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。

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

    transient的用途

    Q:transient关键字能实现什么?

    A:当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。例如,当反序列化对象——数据流(例如,文件)可能不存在时,原因是你的对象中存在类型为java.io.InputStream的变量,序列化时这些变量引用的输入流无法被打开。

    transient使用介绍

    Q:如何使用transient?

    A:包含实例变量声明中的transient修饰符。片段1提供了小的演示。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    import java.io.DataInputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
     
    class ClassLib implements Serializable {
        private transient InputStream is;
     
        private int majorVer;
        private int minorVer;
     
        ClassLib(InputStream is) throws IOException {
            System.out.println("ClassLib(InputStream) called");
            this.is = is;
            DataInputStream dis;
            if (is instanceof DataInputStream)
                dis = (DataInputStream) is;
            else
                dis = new DataInputStream(is);
            if (dis.readInt() != 0xcafebabe)
                throw new IOException("not a .class file");
            minorVer = dis.readShort();
            majorVer = dis.readShort();
        }
     
        int getMajorVer() {
            return majorVer;
        }
     
        int getMinorVer() {
            return minorVer;
        }
     
        void showIS() {
            System.out.println(is);
        }
    }
     
    public class TransDemo {
        public static void main(String[] args) throws IOException {
            if (args.length != 1) {
                System.err.println("usage: java TransDemo classfile");
                return;
            }
            ClassLib cl = new ClassLib(new FileInputStream(args[0]));
            System.out.printf("Minor version number: %d%n", cl.getMinorVer());
            System.out.printf("Major version number: %d%n", cl.getMajorVer());
            cl.showIS();
     
            try (FileOutputStream fos = new FileOutputStream("x.ser");
                    ObjectOutputStream oos = new ObjectOutputStream(fos)) {
                oos.writeObject(cl);
            }
     
            cl = null;
     
            try (FileInputStream fis = new FileInputStream("x.ser");
                    ObjectInputStream ois = new ObjectInputStream(fis)) {
                System.out.println();
                cl = (ClassLib) ois.readObject();
                System.out.printf("Minor version number: %d%n", cl.getMinorVer());
                System.out.printf("Major version number: %d%n", cl.getMajorVer());
                cl.showIS();
            } catch (ClassNotFoundException cnfe) {
                System.err.println(cnfe.getMessage());
            }
        }
    }

    片段1:序列化和反序列化ClassLib对象

    片段1中声明ClassLib和TransDemo类。ClassLib是一个读取Java类文件的库,并且实现了java.io.Serializable接口,从而这些实例能被序列化和反序列化。TransDemo是一个用来序列化和反序列化ClassLib实例的应用类。

    ClassLib声明它的实例变量为transient,原因是它可以毫无意义的序列化一个输入流(像上面讲述的那样)。事实上,如果此变量不是transient的话,当反序列化x.ser的内容时,则会抛出java.io.NotSerializableException,原因是InputStream没有实现Serializable接口。

    编译片段1:javac TransDemo.java;带一个参数TransDemo.class运行应用:java TransDemo TransDemo.class。你或许会看到类似下面的输出:

    1
    2
    3
    4
    5
    6
    7
    8
    ClassLib(InputStream) called
    Minor version number: 0
    Major version number: 51
    java.io.FileInputStream@79f1e0e0
     
    Minor version number: 0
    Major version number: 51
    null

    以上输出表明:当对象被重构时,没有构造方法调用。此外,is假定默认为null,相比较,当ClassLib对象序列化时,majorVer和minorVer是有值的。

    类中的成员变量和transient

    Q:类中的成员变量中可以使用transient吗?

    A:问题答案请看片段2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class TransDemo {
        public static void main(String[] args) throws IOException {
            Foo foo = new Foo();
            System.out.printf("w: %d%n", Foo.w);
            System.out.printf("x: %d%n", Foo.x);
            System.out.printf("y: %d%n", foo.y);
            System.out.printf("z: %d%n", foo.z);
            try (FileOutputStream fos = new FileOutputStream("x.ser");
                    ObjectOutputStream oos = new ObjectOutputStream(fos)) {
                oos.writeObject(foo);
            }
     
            foo = null;
     
            try (FileInputStream fis = new FileInputStream("x.ser");
                    ObjectInputStream ois = new ObjectInputStream(fis)) {
                System.out.println();
                foo = (Foo) ois.readObject();
                System.out.printf("w: %d%n", Foo.w);
                System.out.printf("x: %d%n", Foo.x);
                System.out.printf("y: %d%n", foo.y);
                System.out.printf("z: %d%n", foo.z);
            } catch (ClassNotFoundException cnfe) {
                System.err.println(cnfe.getMessage());
            }
        }
    }

    片段2:序列化和反序列化Foo对象

    片段2有点类似片段1。但不同的是,序列化和反序列化的是Foo对象,而不是ClassLib。此外,Foo包含一对变量,w和x,以及实例变量y和z。

    编译片段2(javac TransDemo.java)并运行应用(java TransDemo)。你可以看到如下输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    w: 1
    x: 2
    y: 3
    z: 4
     
    w: 1
    x: 2
    y: 3
    z: 0

    这个输出告诉我们,实例变量y是被序列化的,z却没有,它被标记transient。但是,当Foo被序列化时,它并没有告诉我们,是否变量w和x被序列化和反序列化,是否只是以普通类初始化方式初始。对于答案,我们需要查看x.ser的内容。

    下面显示x.ser十六进制:

    1
    2
    00000000 AC ED 00 05 73 72 00 03 46 6F 6F FC 7A 5D 82 1D ....sr..Foo.z]..
    00000010 D2 9D 3F 02 00 01 49 00 01 79 78 70 00 00 00 03 ..?...I..yxp....

    由于JavaWorld中的“The Java serialization algorithm revealed”这篇文章,我们发现输出的含义:

    • AC ED 序列化协议标识
    • 00 05 流版本号
    • 73 表示这是一个新对象
    • 72 表示这是一个新的类
    • 00 03 表示类名长度(3)
    • 46 6F 6F 表示类名(Foo)
    • FC 7A 5D 82 1D D2 9D 3F 表示类的串行版本标识符
    • 02 表示该对象支持序列化
    • 00 01 表示这个类的变量数量(1)
    • 49 变量类型代码 (0×49, 或I, 表示int)
    • 00 01 表示变量名长度(1)
    • 79 变量名称(y)
    • 78 表示该对象可选的数据块末端
    • 70 表示我们已经到达类层次结构的顶部
    • 00 00 00 03 表示y的值(3)

    显而易见,只有实例变量y被序列化。因为z是transient,所以不能序列化。此外,即使它们标记transien,w和x不能被序列化,原因是它们类变量不能序列化。

    原文链接: javaworld 翻译: ImportNew.com xbing
    译文链接: http://www.importnew.com/12611.html

  • 相关阅读:
    Tornado之异步authenticated
    使用Tornado和协程爬取博客园文章
    Python协程与asyncio
    Mr.Jin系统发布报告——WIN7 WIN8双系统下的学习模式系统
    Matlab:fsolve No solution found.
    Matlab R2016b下载 安装及破解教程
    第一行代码近期bug及解决
    Android Studio打包生成APK教程
    Notification通知在OPPO手机上不弹出提示?
    Android Studio如何在命令提示符中使用ADB指令
  • 原文地址:https://www.cnblogs.com/zhuyeshen/p/10985225.html
Copyright © 2020-2023  润新知