【转】在Java中如何使用transient

原文链接 http://www.importnew.com/12611.html

 
本文由 ImportNew - xbing 翻译自 javaworld。欢迎加入翻译小组。转载请见文末要求。

 Java语言的transient不像class、synchronized和其他熟悉的关键字那样众所周知,

因而它会出现在一些面试题中。这篇文章我将为大家讲解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());
        }
    }
}
 
class Foo implements Serializable
{
public static int w = 1;
public static transient int x = 2;
public int y = 3;
public transient int z = 4;
}

片段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。

但是这个输出并没有告诉我们,是否变量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
转载请保留原文出处、译者和译文链接。]

关于作者: xbing

 

:::

英文原文写的非常好,只是翻译。。。。。

 

posted on 2015-08-24 13:19  develooop  阅读(277)  评论(0编辑  收藏  举报

导航

AmazingCounters.com