网站首页 > 技术文章 正文
技术背景
在Java编程中,序列化是一个重要的概念。序列化是指将对象的状态转换为字节流的过程,以便将其持久化存储(如保存到文件)或在网络中传输。而反序列化则是将字节流恢复为对象状态的过程。在某些情况下,我们可能不希望对象的某些字段参与序列化过程,这时就需要用到transient关键字。
实现步骤
理解序列化
要使用transient关键字,首先要理解序列化的概念。在Java中,要使一个类的对象能够被序列化,该类必须实现Serializable接口,这是一个标记接口,没有任何方法。示例如下:
import java.io.Serializable;
class MyClass implements Serializable {
// 类的成员变量和方法
}
使用transient关键字
当一个类实现了Serializable接口后,默认情况下,类的所有非静态成员变量都会被序列化。如果希望某个成员变量不被序列化,可以将其声明为transient。示例如下:
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();
}
}
序列化和反序列化对象
以下是一个完整的示例,展示了如何进行对象的序列化和反序列化:
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);
}
}
在上述示例中,middleName被声明为transient,因此在反序列化后,middleName的值为null。
核心代码
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 GalleryImage implements Serializable {
private Image image;
private transient Image thumbnailImage;
private void generateThumbnail() {
// 生成缩略图
}
private void readObject(ObjectInputStream inputStream)
throws IOException, ClassNotFoundException {
inputStream.defaultReadObject();
generateThumbnail();
}
}
public class Main {
public static void main(String[] args) throws Exception {
GalleryImage galleryImage = new GalleryImage();
// 假设初始化image
// galleryImage.image = ...;
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("galleryImage.ser"));
oos.writeObject(galleryImage);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("galleryImage.ser"));
GalleryImage deserializedImage = (GalleryImage) ois.readObject();
ois.close();
}
}
在这个示例中,thumbnailImage被声明为transient,在序列化时不会被保存。在反序列化时,通过重写readObject方法重新生成缩略图。
最佳实践
标记可推导的字段
如果一个字段的值可以从其他字段推导出来,那么可以将其标记为transient。例如,一个表示利息的字段interest,其值可以通过本金、利率和时间计算得出,就不需要将其序列化。
避免序列化敏感信息
对于包含敏感信息的字段,如密码、信用卡号等,应该将其标记为transient,以防止这些信息在序列化过程中被泄露。
处理不可序列化的对象
如果类中包含不可序列化的对象,如Thread、Socket等,应该将这些对象的引用标记为transient,否则在序列化时会抛出NotSerializableException异常。
常见问题
为什么不使用注解@DoNotSerialize
这是因为在Java引入注解之前,transient关键字就已经存在了。在当时,使用关键字是一种简单有效的解决方案。
静态字段是否需要标记为transient
静态字段不会被序列化,因为静态字段属于类,而不是对象。所以即使不标记为transient,静态字段也不会参与序列化过程。但如果为了代码的可读性和明确性,也可以将其标记为transient。
transient字段在反序列化后的值是什么
transient字段在反序列化后的值为其默认值,如引用类型为null,基本类型为相应的默认值(如int为0,boolean为false等)。如果需要在反序列化后对transient字段进行初始化,可以重写readObject方法。
猜你喜欢
- 2025-05-27 Python进阶 - day1:深入理解数据结构
- 2025-05-27 深度学习数据集处理常用函数示例(Python)
- 2025-05-27 Go语言-指针
- 2025-05-27 什么是 happens-before 规则?
- 2025-05-27 「Java」一张图教会你关于null的几种处理方式(内附代码)
- 2025-05-27 Python 中常用的数据结构,帮助你从基础到精通
- 2025-05-27 1、数值类型
- 2025-05-27 基础函数20例,案例解读,再不掌握就真的Out了
- 2025-05-27 12 个 C# 提效实用干货
- 2025-05-27 Java中数组的声明和初始化方法
- 05-27Python进阶 - day1:深入理解数据结构
- 05-27Java中transient字段的作用
- 05-27深度学习数据集处理常用函数示例(Python)
- 05-27Go语言-指针
- 05-27什么是 happens-before 规则?
- 05-27「Java」一张图教会你关于null的几种处理方式(内附代码)
- 05-27Python 中常用的数据结构,帮助你从基础到精通
- 05-271、数值类型
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- sqlset (64)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)