在Java中如何使用transient

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

[email protected]

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不能被序列化,原因是它们类变量不能序列化。

时间: 2024-10-05 13:10:26

在Java中如何使用transient的相关文章

Java中的关键字 transient

在讨论transient之前,有必要先搞清楚Java中序列化的含义: Java中对象的序列化指的是将对象转换成以字节序列的形式来表示,这些字节序列包含了对象的数据和信息,一个序列化后的对象可以被写到数据库或文件中,也可用于网络传输,一般当我们使用缓存cache(内存空间不够有可能会本地存储到硬盘)或远程调用rpc(网络传输)的时候,经常需要让我们的实体类实现Serializable接口,目的就是为了让其可序列化. 当然,序列化后的最终目的是为了反序列化,恢复成原先的Java对象,要不然序列化后干

java中 static,final,transient,volatile关键字的作用

static 和final static  静态修饰关键字,可以修饰 变量,程序块,类的方法: 当你定义一个static的变量的时候jvm会将将其分配在内存堆上,所有程序对它的引用都会指向这一个地址而不会重新分配内存: 修饰一个程序块的时候(也就是直接将代码写在static{...}中)时候,虚拟机就会优先加载静态块中代码,这主要用于系统初始化:当修饰一个类方法时候你就可以直接通过类来调用而不需要新建对象. final 只能赋值一次:修饰变量.方法及类,当你定义一个final变量时,jvm会将其

java中static、transient修饰的属性不能被序列化

相关网页:Java序列化的高级认识http://www.360doc.com/content/13/0728/18/13247663_303173972.shtml 以下程序来自"http://bbs.csdn.net/topics/390155251"(已验证) 类Student1 package test; import java.io.Serializable; public class Student1 implements Serializable{ private stat

java 中 transient 关键字意义

译文出处:Why does Java have transient variables? java 中的 transient 关键字表明了 transient 变量不应该被序列化(transient). 参考Java Language Specification, Java SE 7 Edition, Section 8.3.1.3. transient Fields: 被 transient 标记的这些变量,表明他们是某个对象中不需要被持久状态的部分(Variables may be mark

java中不常见的keyword:strictfp,transient

1.strictfp, 即 strict float point (精确浮点). strictfp keyword可应用于类.接口或方法.使用 strictfp keyword声明一个方法时,该方法中全部的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范.当对一个类或接口使用 strictfp keyword时,该类中的全部代码,包含嵌套类型中的初始设定值和代码,都将严格地进行计算.严格约束意味着全部表达式的结果都必须是 IEEE 754 算法对操作数预

Java中的transient关键字,在移动开发中的使用

transient关键词修饰的属性是临时的,不会被序列化.那么开发移动接口的同志们应该特别注意使用,这样可以提高不少效率.当然其他方面也要适当使用,通过这个特性,可以提高序列化的效率! 百度解释如下,看似别扭难理解,明天去公司写段代码上海,让大家参考下! Java中的transient关键字,在移动开发中的使用,码迷,mamicode.com

Java中的transient,volatile和strictfp关键字

如果用transient声明一个实例变量,当对象存储时,它的值不需要维持.例如: Java代码   class T { transient int a;  //不需要维持 int b;  //需要维持 } 这里,如果T类的一个对象写入一个持久的存储区域,a的内容不被保存,但b的将被保存.     volatile修饰符告诉编译器被volatile修饰的变量可以被程序的其他部分改变.在多线程程序中,有时两个或更多的线程共享一个相同的实例变量.考虑效率问题,每个线程可以自己保存该共享变量的私有拷贝.

关于Java中的transient关键字

Java中的transient关键字是在序列化时候用的,如果用transient修饰变量,那么该变量不会被序列化. 下面的例子中创建了一个Student类,有三个成员变量:id,name,age.age字段被transient修饰,当该类被序列化的时候,age字段将不被序列化. 1 import java.io.Serializable; 2 public class Student implements Serializable{ 3 int id; 4 String name; 5 tran

Java中的Serializable接口和transient关键字

Java中的Serializable接口和transient关键字 Table of Contents 1. 向memcached中放数据时遇到NotSerializableException异常 2. 问题排查和解决 3. 总结 1 向memcached中放数据时遇到NotSerializableException异常 项目中用到了memcached缓存,存储客户的组织结构,以便提高系统性能.之前系统运行正常,近期为了和Portal对接,更新了涉及到组织结构的jar包(由公司产品部门维护),更