JAVA transient 关键字作用详解

2025-11-28 19:50

本文主要是介绍JAVA transient 关键字作用详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《JAVAtransient关键字作用详解》Java的transient关键字用于修饰成员变量,使其不参与序列化过程,通过自定义序列化方法,可以手动控制transient变量的序列化行为,本文给大...

一、transient关键字作用

  • 作用transient 用于修饰成员变量,表示该变量不参与序列化过程。
  • 场景:当对象被序列化(如写入磁盘、通过网络传输)时,transient 修饰的变量不会被保存到序列化流中。

二、原理详解

Java 的对象序列化机制(如 ObjectOutputStream)会将对象的所有非静态、非瞬态(transient)成员变量序列化到字节流中。
transient 关键字告诉 JVM:该变量是临时的,不需要序列化。

反序列化时transient 变量会被赋予默认值(如 int 为 0,引用类型为 null)。

三、典型使用场景

  • 敏感信息
  • 如密码、身份证号等,www.chinasem.cn不希望被序列化存储或传输。
  • 临时计算结果
  • 如缓存、临时状态,不需要持久化。
  • 不可序列化对象
  • 某些成员变量类型没有实现 Serializable,可以用 transient 跳过。

四、代码示例

import java.io.*;
class User implements Serializable {
    private String username;
    private transient String password; // 不序列化
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
}
public class TransientDemo {
    public static void main(String[] args) throws Exception {
        User user = new User("Tom", "123456");
        // 序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.obj"));
        oos.writeObject(user);
        oos.close();
        // 反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.obj"));
        User user2 = (User) ois.readObject();
        ois.close();
        System.out.println(user2.username); // Tom
        System.out.println(user2.password); // null
    }
}

五、注意事项

  1. 只修饰变量,不能修饰方法、类、局部变量。
  2. 静态变量不参与序列化,即使没有 transient 修饰,也不会被序列化。
  3. 自定义序列化:如果实现了 writeObject 和 readObject,可以手动控制 transient 变量的序列化行为。

六、与 static 的区别

  • static 修饰的变量属于类,不属于对象,不参与序列化。
  • transient 修饰的变量属于对象,但被标记为不参与序列化。

七、面试常见问题

  • transient 变量能否被序列化?
    • 默认不会被序列化,但可以通过自定义序列化方法手动序列化。
  • 序列化后 transient 变量的值是什么?
    • 反序列化后为默认值(int 为 0,引用类型为 null)。
  • transient 和 static 有什么区别?
    • static 不参与序列化,transient 标记为不参与序列化。
  • 为什么要用 transient?
    • 保护敏感信息、优化存储、避免不可序列化成员导致序列化失败。

八、补充:自定义序列化 transient 变量

如果你想让 transient 变量也能序列化,可以自定义 writeObject/readObject:

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject();
    oos.writeObject(password); // 手动序列化
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    password = (String) ois.readObject(); // 手动反序列化
}

九、总结表

特性说明
作用标记变量不参与序列化
默认值反序列化后为默认值
修饰对象只能修饰成员变量
典型场景敏感信息/临时变量/不可序列化对象
可否自定义可通过 writeObject/readObject 手动处理

十. 序列化机制与 transient 的底层原理

Java 的序列化机制通过 ObjectOutputStream 和 ObjectInputStream 实现。序列化时,JVM 会遍历对象的所有字段,只有满足以下条件的字段才会被序列化:

  • 非 static
  • 非 transient
  • 类型实现了&nbandroidsp;Serializable 接口

transient 的本质
JVM 在序列化对象时,会判断字段是否被 transient 修饰,如果是,则跳过该字段,不写入字节流。

十一. 常见误区与陷阱

误区一:transient 修饰的变量绝对不会被序列化

实际情况:如果你自定义了 writeObject/readObject 方法,可以手动序列化 transient 字段。

误区二:transient 只能用于敏感信息

实际情况:transient 还可以用于临时计算、缓存、不可序列化成员等场景。

误区三:static transient 有意义

实际情况:static 字段本身就不会被序列化,transient 修饰 static 字段没有任何作用。

十二. 进阶应用:自定义序列化 transient 字段

有时你希望 transient 字段能被序列化,但不想默认序列化,可以自定义序列化方法:

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject(); // 序列化非transient字段
    oos.writeObject(this.transientField); // 手动序列化transient字段
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    ois.defaultReadObject(); // 反序列化非transient字段
    this.transientField = (Type) ois.readObject(); // 手动反序列化transient字段
}

十三. 实际应用场景扩展

  • 分布式系统:如 RPC 框架、缓存对象,常用 transient 跳过网络不需要传输的本地状态。
  • 安全与合规:如日志审计、敏感数据脱敏,防止敏感信息被持久化或泄露。
  • 性能优化:减少序列化内容,提升网络传输和磁盘存储效率。
  • 不可序列化对象:如数据库连接、线程池等,这些对象不能序列化,否则会报错。

十四. 面试陷阱代码分析

陷阱一:

class Test implemandroidents Serializable {
    private transient int a = 10;
    private int b = 20;
}

如果序列化后反序列化,a 的值是多少?
答案: 0(int 默认值),b 是 20。

陷阱二:

class Test implements Serializable {
    private static transient int a = 10;
}

序列化后反序列化,a 的值是多少?
答案: 10(static 字段不会被序列化,值取决于类加载时的静态初始NrvlCExi化)

十五. transient 与其他关键字的对比

关键字作用是否序列化
transient标记不序列化成员变量
static类变量,不属于对象
final常量,只能赋值一次

十六. 进阶:transient 与可变对象

如果 transient 修饰的是引用类型变量(如 List),反序列化后会变为 null。
如果需要恢复数据,可以在 readObject 方法里初始化或重建。

十七. 典型面试题总结

  • transient 修饰的变量序列化后会是什么?
    • 对于基本类型,是默认值;对于引用类型,是 null。
  • transient 可以修饰 static 吗?
    • 可以,但没有实际意义。
  • transient 变量能否通过自定义序列化保存?
    • 可以,需实现 writeObject/readObject 方法。
  • 为什么要用 transient?
    • 安全、NrvlCExi性能、避免不可序列化成员导致异常。

十八. 补充:序列化版本号与 transient

  • serialVersionUID 是 static final 字段,不参与序列化。
  • 如果类结构变化,反序列化可能失败,transient 字段不会影响序列化兼容性。

十九.transient与序列化机制的深层关系

1 序列化的过程

  • Java 的序列化机制会递归地序列化对象的每个非 static、非 transient 字段。
  • 如果字段类型本身不可序列化(没有实现 Serializable),但未被 transient 修饰,序列化会抛出 NotSerializableException

2 反序列化过程

  • 反序列化时,transient 字段不会从流中恢复,直接赋予默认值。
  • 如果你希望反序列化后给 transient 字段赋初值,可以用如下方式:
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    this.transientField = ...; // 这里可以初始化
}

二十.transient相关的安全问题

1 敏感数据泄露

  • 如果敏感字段未被 transient 修饰,序列化后可能被写入磁盘或通过网络传输,造成安全隐患。
  • 建议:对所有敏感信息(如密码、token、身份证号等)都加上 transient。

2 反序列化漏洞

  • transient 字段不会参与序列化和反序列化,但如果你在 readObject 里对 transient 字段做了不安全的初始化,也可能被攻击者利用(如反序列化 gadget 链)。

二十一. 性能优化相关

  • 对于大对象,如果某些字段无需持久化,使用 transient 可以显著减少序列化数据体积,提高网络传输和存储性能。
  • 在高性能缓存、分布式对象同步等场景,合理使用 transient 能避免不必要的负担。

二十二. 在主流框架中的应用

1 Spring

  • Spring 的 Bean、Session 等对象有时会被序列化传递,常用 transient 跳过如数据库连接、线程池、日志等不可序列化资源。

2 Hibernate/JPA

  • 实体类中有些字段(如 logger、临时缓存)会加 transient,避免持久化和序列化。

3 分布式缓存/消息队列

  • Redis、Kafka、RocketMQ 等都会用到对象序列化,transient 可以跳过本地状态和敏感字段。

二十三. 进阶:transient 与自定义序列化框架

  • Java原生序列化只认 transient,第三方序列化(如 Jackson、Fastjson、Kryo、Protobuf)不一定认 transient。
  • 比如 Jackson 需要配合 @JsonIgnore 注解,而不是 transient。
  • 工程建议:如果需要跨多种序列化框架,建议同时用 transient 和注解(如 @JsonIgnore)双重标记。

二十四. 面试高频“陷阱”与实战建议

1 面试陷阱代码

class Person implements Serializable {
    private transient int age = 18;
    private String name = "Tom";
}

序列化后反序列化,age 是多少?
答案:0(int 默认值),不是 18。

2 实战建议

  • 对所有不可序列化或敏感字段,都加 transient。
  • 如果需要恢复 transient 字段值,建议在 readObject 里初始化。
  • 对于跨多种序列化框架的项目,建议加上相应的注解。

二十五. 结合实际业务场景举例

1 缓存对象

class CacheObject implements Serializable {
    private String data;
    private transient long lastAccessTime; // 仅本地有效
}

2 日志字段

class ServiceBean implements Serializable {
    private String id;
    private transient Logger log = LoggerFactory.getLogger(ServiceBean.class);
}

3 线程池、数据库连接等资源

class Job implements Serializable {
    private transient ExecutorService threadPool;
    private transient Connection dbConn;
}

二十六. 小结

  • transient 是 Java 原生序列化机制的关键字,主要用于跳过不需要序列化的字段。
  • 适用于敏感信息、临时状态、不可序列化成员、性能优化等多种场景。
  • 结合自定义序列化,可以灵活控制序列化和反序列化行为。
  • 在分布式、缓存、框架开发等实际工程中非常常见。
  • transient 用于控制序列化行为,保护敏感信息,优化性能,处理不可序列化成员。
  • 反序列化后 transient 字段为默认值。
  • 可通过自定义序列化方法手动保存/恢复 transient 字段。

到此这篇关于JAVA transient 关键字详解的文章就介绍到这了,更多相关java transient 关键字内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于JAVA transient 关键字作用详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1156302

相关文章

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

MySQL中between and的基本用法、范围查询示例详解

《MySQL中betweenand的基本用法、范围查询示例详解》BETWEENAND操作符在MySQL中用于选择在两个值之间的数据,包括边界值,它支持数值和日期类型,示例展示了如何使用BETWEEN... 目录一、between and语法二、使用示例2.1、betwphpeen and数值查询2.2、be

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Java中ArrayList与顺序表示例详解

《Java中ArrayList与顺序表示例详解》顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,:本文主要介绍Java中ArrayList与... 目录前言一、Java集合框架核心接口与分类ArrayList二、顺序表数据结构中的顺序表三、常用代码手动

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程