Java 中的 transient 关键字:深入解析与实战

在 Java 编程中,transient 关键字是一个非常有用的工具,尤其是在处理对象序列化时。尽管 transient 关键字在日常开发中可能不常被使用,但了解它的作用和使用场景对于提升代码的安全性和性能至关重要。本文将深入探讨 transient 关键字的作用、使用方法以及一些注意事项。

1 transient 的作用及使用方法

在 Java 中,一个对象只要实现了 Serializable 接口,它就可以被序列化。然而,在实际开发过程中,我们常常会遇到这样的情况:一个类的某些字段需要序列化,而另一些字段则不需要。例如,用户的敏感信息(如密码、银行卡号等)为了安全起见,不希望在网络操作中传输或持久化到磁盘文件中。这时,我们就可以使用 transient 关键字来标记这些字段。

示例

public class TransientTest {public static void main(String[] args) {User user = new User();user.setUsername("沉默王二");user.setPasswd("123456");System.out.println("read before Serializable: ");System.out.println("username: " + user.getUsername());System.err.println("password: " + user.getPasswd());try {ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("user.txt"));os.writeObject(user); // 将User对象写进文件os.flush();os.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}try {ObjectInputStream is = new ObjectInputStream(new FileInputStream("user.txt"));user = (User) is.readObject(); // 从流中读取User的数据is.close();System.out.println("\nread after Serializable: ");System.out.println("username: " + user.getUsername());System.err.println("password: " + user.getPasswd());} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}
}class User implements Serializable {private static final long serialVersionUID = 8294180014912103005L;  private String username;private transient String passwd;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPasswd() {return passwd;}public void setPasswd(String passwd) {this.passwd = passwd;}
}

输出结果:

read before Serializable:
username: 沉默王二
password: 123456 
read after Serializable:
username: 沉默王二
password: null

从输出结果可以看出,password 字段为 null,说明反序列化时根本没有从文件中获取到该字段的信息。

2 transient 使用小结

  1. 一旦字段被 transient 修饰,该成员变量将不再是对象持久化的一部分,该变量的值在序列化后无法访问。
  2. transient 关键字只能修饰字段,而不能修饰方法和类。
  3. transient 关键字修饰的字段不能被序列化,一个静态变量(static 关键字修饰)不管是否被 transient 修饰,均不能被序列化。

示例

public class TransientTest {public static void main(String[] args) {User user = new User();user.setUsername("沉默王二");user.setPasswd("123456");System.out.println("read before Serializable: ");System.out.println("username: " + user.getUsername());System.err.println("password: " + user.getPasswd());try {ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("user.txt"));os.writeObject(user); // 将User对象写进文件os.flush();os.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}try {// 在反序列化之前改变username的值User.username = "沉默王三";ObjectInputStream is = new ObjectInputStream(new FileInputStream("user.txt"));user = (User) is.readObject(); // 从流中读取User的数据is.close();System.out.println("\nread after Serializable: ");System.out.println("username: " + user.getUsername());System.err.println("password: " + user.getPasswd());} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}
}class User implements Serializable {private static final long serialVersionUID = 8294180014912103005L;  public static String username;private transient String passwd;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPasswd() {return passwd;}public void setPasswd(String passwd) {this.passwd = passwd;}
}

运行结果:

read before Serializable:
username: 沉默王二
password: 123456 
read after Serializable:
username: 沉默王三
password: null

从结果可以看出,username 字段在反序列化后变成了 沉默王三,这证明了 static 修饰的字段不能被序列化。

3 transient 修饰的字段真的不能被序列化?

思考下面的例子:

public class ExternalizableTest implements Externalizable {private transient String content = "是的,我将会被序列化,不管我是否被transient关键字修饰";@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeObject(content);}@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {content = (String) in.readObject();}public static void main(String[] args) throws Exception {ExternalizableTest et = new ExternalizableTest();ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File("test")));out.writeObject(et);ObjectInput in = new ObjectInputStream(new FileInputStream(new File("test")));et = (ExternalizableTest) in.readObject();System.out.println(et.content);out.close();in.close();}
}

输出结果:

是的,我将会被序列化,不管我是否被transient关键字修饰

这是为什么呢?不是说 transient 关键字修饰的字段不能序列化吗?

这是因为我们使用了 Externalizable 接口而不是 Serializable 接口。在 Java 中,对象的序列化可以通过实现两种接口来实现:

  • Serializable 接口:所有的序列化将会自动进行。
  • Externalizable 接口:需要在 writeExternal 方法中指定要序列化的字段,与 transient 关键字修饰无关。

因此,例子中输出的是变量 content 的内容,而不是 null

4 小结

transient 关键字用于修饰类的成员变量,在序列化对象时,被修饰的成员变量不会被序列化和保存到文件中。其作用是告诉 JVM 在序列化对象时不需要将该变量的值持久化,这样可以避免一些安全或者性能问题。但是,transient 修饰的成员变量在反序列化时会被初始化为其默认值(如 int 类型会被初始化为 0,引用类型会被初始化为 null),因此需要在程序中进行适当的处理。

transient 关键字和 static 关键字都可以用来修饰类的成员变量。其中,transient 关键字表示该成员变量不参与序列化和反序列化,而 static 关键字表示该成员变量是属于类的,不属于对象的,因此不需要序列化和反序列化。

SerializableExternalizable 接口中,transient 关键字的表现也不同:

  • Serializable 中,transient 表示该成员变量不参与序列化和反序列化。
  • Externalizable 中,transient 不起作用,因为 Externalizable 接口需要实现 readExternalwriteExternal 方法,需要手动完成序列化和反序列化的过程。

通过深入理解 transient 关键字,我们可以更好地控制对象的序列化过程,从而提升代码的安全性和性能。

5 思维导图

在这里插入图片描述

6 参考链接

招银面试官:说说 Java transient 关键字吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/466022.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)

一、App 渠道来源追踪概述 渠道来源统计/追踪,其原理都可以称之为归因,归因是用于判断用户在什么原因、什么时间、什么场景下载了 App,以及打通他们在激活 App 后进行的一系列操作(比如注册、付费、加购等)。 渠道来…

参数跟丢了之JS生成器和包装器

如需转载请注明出处.欢迎小伙伴一起讨论技术. 逆向网址:aHR0cHM6Ly91bmlvbi5qZC5jb20vcHJvTWFuYWdlci9pbmRleD9wYWdlTm89MQ 跟踪接口:aHR0cHM6Ly9hcGkubS5qZC5jb20vYXBp 跟踪参数:h5st 本文目标:记录学习下自定义的生成器和包装器,不做具体的参数加密逻辑分析 直接启动器进…

Redis集群——针对实习面试

目录 Redis集群Redis集群解决了什么问题?Redis集群是如何分片的?什么是Sentinel?Redis如何使用哨兵(Sentinel)系统?集群如何进行故障转移?Redis集群中的主从复制模型是怎样的?Redis集…

【种完麦子,我就往南走,去西双版纳,过个冬天!】

麦子奶奶:冰哥,你好。 大冰:你好,咱俩不定谁大呢。 麦子奶奶:嗯,我大,我60多了,你各方面都是哥。 大冰:阿姨好 麦子奶奶:我想出去看看祖国的大好河山&…

长亭那个检测能力超强的 WAF,出免费版啦

告诉你们一个震撼人心的消息,那个检测能力超强的 WAF——长亭雷池,他推出免费社区版啦,体验地址见文末。 八年前我刚从学校毕业,在腾讯做安全研究,看到宇森在 BlackHat 上演讲的议题 《永别了,SQL 注入》 …

Elasticsearch+kibana+filebeat的安装及使用

版本7.6.0 自己去官网下载或者私信找我要,jdk是8版本 1.ES安装 网上有好多安装教程可以自己去搜索 这个是我的es文件路径: { “name” : “node-1”, “cluster_name” : “elasticsearch”, “cluster_uuid” : “NIepktULRfepkje3JHw8NA”, “ve…

NVR小程序接入平台/设备EasyNVR多品牌NVR管理工具/设备汇聚公共资源场景方案全析

随着信息技术的飞速发展,视频监控已经成为现代社会安全管理和业务运营不可或缺的一部分。特别是在公共资源管理方面,视频监控的应用日益广泛,涵盖了智慧城市、智能交通、大型企业以及校园安防等多个领域。NVR小程序接入平台EasyNVR作为一款功…

ThingsBoard规则链节点:RPC Call Reply节点详解

引言 1. RPC Call Reply 节点简介 2. 节点配置 2.1 基本配置示例 3. 使用场景 3.1 设备控制 3.2 状态查询 3.3 命令执行 4. 实际项目中的应用 4.1 项目背景 4.2 项目需求 4.3 实现步骤 5. 总结 引言 ThingsBoard 是一个开源的物联网平台,提供了设备管理…

【论文复现】基于图卷积网络的轻量化推荐模型

本文所涉及所有资源均在这里可获取。 📕作者简介:热爱跑步的恒川,致力于C/C、Java、Python等多编程语言,热爱跑步,喜爱音乐、摄影的一位博主。 📗本文收录于论文复现系列,大家有兴趣的可以看一看…

sql数据库-DQL-基本查询

目录 举例表emp 查询多个字段 查询整张表所有数据 给字段名起别名(更方便阅读) 去除重复的数据 举例表emp 查询多个字段 SELECT 字段1,字段2,字段3...FROM 表名; 举例查询emp表中的name,workno,age字段返回 查询整张表所有数据 …

OpenCV通过指针裁剪图像

OpenCV 中mat 格式的像素数值都是连续排列的。为了深入了解cuda 编程。我们来写一个简单的小程序测试一下。 1 不裁剪 cv::Mat crop_image(int(height), int(width), CV_8UC3, image.data);2 只保留图像1/3 cv::Mat crop_image(int(height/3), int(width), CV_8UC3, image.da…

Perforce《2024游戏技术现状报告》Part2:游戏引擎、版本控制、IDE及项目管理等多种开发工具的应用分析

游戏开发者一直处于创新前沿。他们的实践、工具和技术受到各行各业的广泛关注,正在改变着组织进行数字创作的方式。 近期,Perforce发布了《2024游戏技术现状报告》,通过收集来自游戏、媒体与娱乐、汽车和制造业等高增长行业的从业者、管理人…

软件测试面试题及答案

以下是软件测试相关的面试题及答案! 1、测试分为哪几个阶段? 一般来说分为5个阶段:单元测试、集成测试、确认测试、系统测试、验收测试 2、软件测试的流程是什么? 需求调查:全面了解系统概况、应用领域、软件开发周期、软件开发环境、开发组织、时…

Python实例:爱心代码

前言 在编程的奇妙世界里,代码不仅仅是冰冷的指令集合,它还可以成为表达情感、传递温暖的独特方式。今天,我们将一同探索用 Python 语言绘制爱心的神奇之旅。 爱心,这个象征着爱与温暖的符号,一直以来都在人类的情感世界中占据着特殊的地位。而通过 Python 的强大功能,…

TypeError: can‘t multiply sequence by non-int of type ‘float‘

通过python程序编写excel表格中的数据,在计算数值时出现数值类型错误: TypeError: cant multiply sequence by non-int of type float 问题分析: 读取的Excel文件中的单元格数据,读取的数值有可能不是数值类型,而是含…

行业人才缺口达百万,无人机“飞手”之渴如何解?0基础无人机学习技术详解

针对无人机“飞手”行业人才缺口达百万的问题,以下是对如何缓解这一缺口以及0基础学习无人机技术的详细解析: 一、缓解无人机“飞手”人才缺口的方法 1. 产教融合: 通过校企合作、产教融合等方式,培养具备实战能力的无人机“飞手…

D60【python 接口自动化学习】- python基础之数据库

day60 数据库定义 学习日期:20241106 学习目标:MySQL数据库-- 128:数据库定义 学习笔记: 无处不在的数据库 数据库如何存储数据 数据库管理系统(数据库软件) 数据库和SQL的关系 总结 数据库就是指数据…

React中类组件和函数组件的理解和区别

react代码模块分为类组件和函数组件。 从语法和定义、内部状态管理、生命周期、性能、可读性和维护性、上下文、集成状态管理库等角度对比React中类组件和函数组件。 1、语法和定义 类组件: 使用 ES6 的类(class)语法定义的 React 组件。…

苹果 CMS 原生 Java 白菜影视 App 源码

源码介绍 苹果 CMS 原生 Java 白菜影视 App 源码是一款功能强大的影视应用程序,支持画中画、投屏、点播、播放前广告和支持普通解析等多种功能。与萝卜 App 源码相比,该套源码更加稳定,且拥有画中画投屏和自定义广告等功能,提高了…

三菱MR-J4-B系列伺服参数一览

要点 与伺服系统控制器连接后,同服系统控制器的伺服参数的值即被写入各参数中。根据伺服系统控制器的机种和伺服放大器软件版本及MRConfigurator2的软件版本,存在无法设定的参数或范围。详细内容请参照伺服系统控制器的用户手册。请使用MR Configurator2…