Java中transient字段的作用及使用场景
技术背景
在Java编程里,序列化是一项关键技术,它能把对象状态转化为字节流,用于存储(如存入文件)或传输(如在网络上发送)。反序列化则是将字节流恢复成对象状态的过程。不过,并非所有对象的字段都需要被序列化,这时就需要transient
关键字来发挥作用。
实现步骤
1. 理解序列化和transient
关键字
在Java中,要让一个类的对象能够被序列化,该类必须实现Serializable
接口。transient
关键字用于标记那些不需要参与序列化过程的字段。
2. 标记transient
字段
在类的定义中,使用transient
关键字标记不需要序列化的字段。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class GalleryImage implements Serializable { private Image image; private transient Image thumbnailImage;
private void generateThumbnail() { }
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); generateThumbnail(); } }
|
3. 反序列化时恢复对象状态
在反序列化时,可能需要手动恢复对象的状态。可以通过重写readObject
方法来实现。如上述示例,在反序列化时调用generateThumbnail
方法生成缩略图。
核心代码
示例一:GalleryImage
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class GalleryImage implements Serializable { private Image image; private transient Image thumbnailImage;
private void generateThumbnail() { }
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); generateThumbnail(); } }
|
示例二:NameStore
类
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
| package javabeat.samples;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable;
class NameStore implements Serializable { private String firstName; private transient String middleName; private String lastName;
public NameStore(String fName, String mName, String lName) { this.firstName = fName; this.middleName = mName; this.lastName = lName; }
public String toString() { StringBuffer sb = new StringBuffer(40); sb.append("First Name : "); sb.append(this.firstName); sb.append("Middle Name : "); sb.append(this.middleName); sb.append("Last Name : "); sb.append(this.lastName); return sb.toString(); } }
public class TransientExample { public static void main(String args[]) throws Exception { NameStore nameStore = new NameStore("Steve", "Middle", "Jobs"); ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("nameStore")); o.writeObject(nameStore); o.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("nameStore")); NameStore nameStore1 = (NameStore) in.readObject(); System.out.println(nameStore1); } }
|
最佳实践
- 避免序列化不必要的字段:对于那些可以从其他字段推导出来的字段,或者在反序列化时可以重新计算的字段,应标记为
transient
,以减少序列化对象的存储空间。 - 重写
readObject
方法:在反序列化时,如果需要恢复对象的状态,可以重写readObject
方法,在其中进行必要的操作。
常见问题
1. transient
字段在反序列化后的值是什么?
transient
字段在反序列化后的值为其默认值,如引用类型为null
,基本类型为对应基本类型的默认值。
2. 静态字段需要标记为transient
吗?
静态字段不会被序列化,因为静态字段属于类,而不是对象。不过,如果出于设计考虑,也可以将其标记为transient
。
3. transient
字段可以是局部变量吗?
不可以,transient
关键字只能用于类的成员变量,不能用于局部变量。