当前位置: 首页 > 编程日记 > 正文

transient HashMap使用目的分析

看HashSet源码有这么一句:

private transient HashMap<E,Object> map;

再看HashSet的Add方法:

实际上HashSet是复用HashMap了。

而我们去看看HashMap也会发现一样使用了transient

而不管是HashSet还是HashMapdou都要求是Serializable的:

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {
public class HashSet<E>extends AbstractSet<E>implements Set<E>, Cloneable, java.io.Serializable

而transient实际上是不序列化的,这就好像有点“矛盾”,再回答这个问题之前先看看transient。

测试代码如下:

import java.io.Serializable;public class EmployeeTransient implements Serializable {public String getConfidentialInfo() {return confidentialInfo;}public void setConfidentialInfo(String confidentialInfo) {this.confidentialInfo = confidentialInfo;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}private transient String confidentialInfo;private String firstName;private String lastName;
}

现在让我们先序列化再反序列化回java对象,并验证是否保存了“ confidentialInfo ”?

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class TransientTest {public static void main(String args[]) {try {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("empInfo.ser"));EmployeeTransient emp = new EmployeeTransient();emp.setFirstName("Lokesh");emp.setLastName("Gupta");emp.setConfidentialInfo("password");//Serialize the objectoos.writeObject(emp);oos.close();} catch (Exception e) {System.out.println(e);}try {ObjectInputStream ooi = new ObjectInputStream(new FileInputStream("empInfo.ser"));//Read the object backEmployeeTransient readEmpInfo = (EmployeeTransient) ooi.readObject();System.out.println(readEmpInfo.getFirstName());System.out.println(readEmpInfo.getLastName());System.out.println(readEmpInfo.getConfidentialInfo());ooi.close();} catch (Exception e) {System.out.println(e);}}
}

很明显,“ confidentialInfo ”在序列化时没有保存到持久状态,这正是我们在java中使用“ transient ”关键字的原因。

什么时候应该在java中使用transient关键字?

现在我们对“ transient  ”关键字非常了解。让我们通过确定您需要使用transient关键字的情况来扩展理解。

  1. 第一个也是非常合乎逻辑的情况是,您可能拥有类实例中的其他字段派生/计算的字段。应该每次都以编程方式计算它们,而不是通过序列化来保持状态。一个例子可以是基于时间戳的价值; 例如人的年龄或时间戳和当前时间戳之间的持续时间。在这两种情况下,您将根据当前系统时间而不是序列化实例来计算变量的值。
  2. 第二个逻辑示例可以是任何不应以任何形式泄漏到JVM外部的安全信息(在数据库或字节流中)。
  3. 另一个例子可能是在JDK或应用程序代码中未标记为“Serializable”的字段。未实现Serializable接口并在任何可序列化类中引用的类无法序列化; 并将抛出“java.io.NotSerializableException”异常。在序列化主类之前,应将这些不可序列化的引用标记为“transient ”。
  4. 最后,有时候序列化某些字段根本没有意义。期。例如,在任何类中,如果添加了记录器引用,那么序列化该记录器实例的用途是什么。绝对没用。您可以逻辑地序列化表示实例状态的信息。Loggers永远不要分享实例的状态。它们只是用于编程/调试目的的实用程序。类似的例子可以是一个Thread类的引用。线程表示任何给定时间点的进程状态,并且没有用于将线程状态存储到您的实例中; 仅仅因为它们不构成你班级实例的状态。

//final field 1
public final transient String confidentialInfo = "password";

现在当我再次运行序列化(写/读)时,会输出出password。

原因是,只要任何最终字段/引用被评估为“ 常量表达式 ”,它就会被JVM序列化,忽略transient关键字的存在。

如果要保持非可序列化字段的状态,请使用readObject()和writeObject()方法。writeObject()/ readObject()通常在内部链接到序列化/反序列化机制,因此自动调用。 :java中的SerialVersionUID及相关

HashMap如何使用transient关键字?

HashMap用于存储键值对,我们都知道。并且我们还知道内部密钥的位置HashMap是基于例如密钥获得的哈希码来计算的。现在当我们序列化一个HashMap意味着内部的所有键HashMap和键的各个值也将被序列化。序列化后,当我们反序列化HashMap实例时,所有键实例也将被反序列化。我们知道在这个序列化/反序列化过程中,可能会丢失信息(用于计算哈希码),最重要的是它本身就是一个新的实例。

在java中,任何两个实例(即使是同一个类)都不能具有相同的哈希码。这是一个很大的问题,因为根据新的哈希码应该放置键的位置不在正确的位置。检索键的值时,您将在此新HashMap中引用错误的索引。

:在java中使用hashCode和equals方法

因此,当序列化哈希映射时,这意味着哈希索引,因此表的顺序不再有效,不应保留。这是问题陈述。

HashMap类使用writeObject()readObject()方法,如下所示

/*** Save the state of the <tt>HashMap</tt> instance to a stream (i.e.,* serialize it).** @serialData The <i>capacity</i> of the HashMap (the length of the*             bucket array) is emitted (int), followed by the*             <i>size</i> (an int, the number of key-value*             mappings), followed by the key (Object) and value (Object)*             for each key-value mapping.  The key-value mappings are*             emitted in no particular order.*/private void writeObject(java.io.ObjectOutputStream s)throws IOException {int buckets = capacity();// Write out the threshold, loadfactor, and any hidden stuffs.defaultWriteObject();s.writeInt(buckets);s.writeInt(size);internalWriteEntries(s);}
// Callbacks to allow LinkedHashMap post-actionsvoid afterNodeAccess(Node<K,V> p) { }void afterNodeInsertion(boolean evict) { }void afterNodeRemoval(Node<K,V> p) { }// Called only from writeObject, to ensure compatible ordering.void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {Node<K,V>[] tab;if (size > 0 && (tab = table) != null) {for (int i = 0; i < tab.length; ++i) {for (Node<K,V> e = tab[i]; e != null; e = e.next) {s.writeObject(e.key);s.writeObject(e.value);}}}}

下面是HashSet中的实现,思路都是一样的。都是把key,value都写到序列化里去,

/*** Save the state of this <tt>HashSet</tt> instance to a stream (that is,* serialize it).** @serialData The capacity of the backing <tt>HashMap</tt> instance*             (int), and its load factor (float) are emitted, followed by*             the size of the set (the number of elements it contains)*             (int), followed by all of its elements (each an Object) in*             no particular order.*/private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException {// Write out any hidden serialization magics.defaultWriteObject();// Write out HashMap capacity and load factors.writeInt(map.capacity());s.writeFloat(map.loadFactor());// Write out sizes.writeInt(map.size());// Write out all elements in the proper order.for (E e : map.keySet())s.writeObject(e);}

然后反序列化的时候就是重新hash一次的过程

下面是HashMap的readObject:

下面是HashSet的readObject:

使用上面的代码,HashMap仍然可以像通常那样处理非transient字段,但是它们一个接一个地在字节数组的末尾写入存储的键值对。在反序列化时,它会通过默认的反序列化过程处理非transient变量,然后逐个读取键值对。对于每个键,哈希和索引再次计算并插入到表中的正确位置,以便可以再次检索它而不会出现任何错误。

参考:Java transient关键字示例

扩展阅读:

为什么HashMap的哈希表标记为transient,尽管该类是可序列化的

图解集合4:HashMap

相关文章:

4月29日监理师课程作业

软考信息系统监理师&#xff1a;2016年4月29日作业一、信息应用系统分析设计阶段监理1、需求分析的进入条件是什么&#xff1f;&#xff08;记&#xff09;答&#xff1a;①业主单位与承建单位正式签订建设合同&#xff0c;②并对初步的项目开发计划达成一致意见。2、需求分析的…

沉浸式导航栏html,混合开发 h5+ 沉浸式的适配

1.需要在mainfest.json plus对象里添加"statusbar": {"immersed": "true","style":"dark"}2.新建immersed.js注意 在里边不适用plus,因为plus.ready之后再js改变样式 必然造成页面闪烁跳动(function(w){document.addEventLi…

puppet yum模块、配置仓储、mount模块

转载&#xff1a;http://blog.51cto.com/ywzhou/1577335 作用&#xff1a;自动为客户端配置YUM源&#xff0c;为使用yum安装软件包提供便捷。 1、服务端配置yum模块 &#xff08;1&#xff09;模块清单 [rootpuppet ~]# tree /etc/puppet/modules/yum/ /etc/puppet/modules/yum…

最新技术选型解决方案列表

最新技术选型解决方案列表 1 概述 这是一份当前的技术选型方案&#xff0c;针对创业、中小型公司 2 目标2.1 产品目标2.1.1 SaaS 2.1.1.1 免安装 2.1.1.2 多租户 2.1.1.3 流量计费 2.1.2 可配置 2.1.2.1 需开通服务 2.1.2.2 服务自动组合 2.1…

合工大的计算机专业好不好,合肥工业大学计算机好,还是西电的好?差距有多大?...

合肥工业大学计算机好&#xff0c;还是西电的好?差距有多大?这两个大学都是教育部直属的工科院校&#xff0c;但是性质完全不一样&#xff0c;到底谁更厉害&#xff0c;结论是西电的计算机要比合肥工业大学强。首先因为西电本身就是比哈工大厉害的大学&#xff0c;学科评估方…

DataWorks V2使用PyUdf

在DataWorks上新建一个Python资源&#xff0c;命名为 test_udf.py 编辑pyudf的脚本代码&#xff0c;实现方法请参考Python实现MaxCompute UDF # -*- coding:utf-8 -*- from odps.udf import annotate #函数签名&#xff0c;SQL执行前所有函数的参数类型和返回值类型必须确定&a…

Java线程怎样映射到操作系统线程

先说多线程模型&#xff0c;参考经典教材《Operating System Concepts , Silberschatz ,9th edition》 中文版是《操作系统概念&#xff0c;第9版》 https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/4_Threads.html 一个线程是CPU利用率的基本单元&#xff0c;包…

NSUserDefaults的用法

2019独角兽企业重金招聘Python工程师标准>>> NSDictionary* defaults [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]; NSLog("Defaults: %", defaults); 是用来获取设备上的所有的NSUserDefaults的设置。 上面代码输出了 2013-06…

计算机在轻工行业中的应用,计算机在不同领域中的具体应用

计算机以其卓越的性能和强大的生命力&#xff0c;在科学技术、国民经济、社会生活等各个方面得到了广泛的应用&#xff0c;并且取得了明显的社会效益和经济效益。计算机的应用几乎包括人类生活的一切领域&#xff0c;可以说是包罗万象&#xff0c;不胜枚举。据统计&#xff0c;…

自动驾驶L3量产追梦:如何跨过车规级和低成本门槛?

雷锋网新智驾按&#xff1a;从人类设想到落地前行&#xff0c;智能驾驶领域在2018年声响不断。在频繁的融资、技术创新和商业应用等信息背后&#xff0c;无数车企在公司战略中加入“网联化”、“自动化”&#xff0c;前几年涌现的自动驾驶领域的初创公司&#xff0c;近年来也开…

一句话说清聚集索引和非聚集索引以及MySQL的InnoDB和MyISAM

聚集索引和非聚集索引以及MySQL的InnoDB和MyISAM经常遇到有人向我咨询这个问题&#xff0c;其实呢&#xff0c;网上帖子很多&#xff0c;也说的都对&#xff0c;但是呢&#xff0c;看客可不一定是真的理解了。所以今天在这里用最简短的语言让你明白这些区别。 看这种图表就一切…

awstats CGI模式下动态生成页面缓慢的改进

本文可以看做是 多server多站点情况下awstats日志分析 这篇文章的下篇&#xff0c;在使用过程中发现awstats在cgi模式下动态生成分析报告慢的问题 &#xff08;尤其是有些站点每天两个多G的日志&#xff0c;查看起来简直是在考验人的耐性&#xff09;&#xff0c;本文分享一种改…

计算机水平flash试题,计算机flash考试试题

《Flash动画设计》课程考核方案一、考试班级及科目216班 《Flash动画设计》二、考试时间1、考核时间&#xff1a;90分钟2、考试地点&#xff1a;学校计算机3机房3、考核时期&#xff1a;十七、十八周内各课任教师自主选定三、考核形式上机独立完成所有操作。在规定时间内按考核…

CDH大数据集群安全风险汇总

一&#xff0c;风险分为内部和外部 首先内部&#xff1a; CDH大数据集群部署过程中会自动创建以服务命名的用户&#xff0c;如图所示 用户名(login_name)&#xff1a;口令位置(passwd)&#xff1a;用户标识号(UID)&#xff1a;用户组标识号(GID)&#xff1a;注释性描述(users)&…

有界阻塞队列ArrayBlockingQueue和无界阻塞队列LinkedBlockingQueue

ArrayBlockingQueue和LinkedBlockingQueue最大的区别是一个是有界无界&#xff0c;各有优劣。 先看实例代码&#xff1a; main函数起2个线程模拟生成消费者 import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.…

zabbix监控windows 服务器各项性能

Zabbix agent 在windows上安装部署1、 下载与解压地址: http://www.zabbix.com/downloads/2.4.0/zabbix_agents_2.4.0.win.zip解压zabbix_agents_2.4.0.win.zipconf目录存放是agent配置文件 bin文件存放windows下32位和64位安装程序2、 配置与安装2.1 配置zabbix agent相关配…

计算机设备板块超跌,半导体全线拉升,沪指强势突破3600点,午后A股会再次冲高回落吗...

周四开盘沪指开于3585点&#xff0c;和周三收盘价低开了8个点。上午开盘后沪指呈现低开高走的趋势&#xff0c;10点以后沪指持续拉升上涨不但顺利地突破了3600点而且还创了反弹新高。除了沪指以外深市三大股指也是全线翻红&#xff0c;上午A股的三大股指再次全线拉升并且均创了…

docker之基础

一、Docker简介 容器&#xff1a;运行在同一类用户空间上的程序打包在一起&#xff0c;相当于一个集装箱 Docker:码头装运工&#xff1b;把集装箱搬运到该有的位置。 Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器&#xff08;LXC&…

Java一个线程能否结束另一个永不停止的线程

在Java中停止一个线程有三种办法 &#xff1a; 1.正常结束执行&#xff1b; 2.发生异常; 3.被其他线程stop(Java官方不建议) 参考&#xff1a;https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html 为什么Thread.stop弃用…

pxe cobbler ipmi bmc

http://blog.csdn.net/xuensong520/article/details/8922926 http://blog.csdn.net/xuensong520/article/details/8915945 http://www.wenzizone.cn/?p408 #执行外部脚本(后置脚本)vi /var/www/cobbler/ks_mirror/config/autoip.sh #创建脚本&#xff0c;自动设置Linux系统静…

广东电大计算机绘图试题,电大计算机绘图期末复习试题及答案参考小抄.doc

电大计算机绘图期末复习试题及答案参考小抄一、填空题(每小题1.5分&#xff0c;共30分)1&#xff0e;CAD的常用图形输入设备有???鼠标??、数字化仪、图形输入板、光笔、??键盘 等。2&#xff0e;CAD的软件可分为系统软件、支撑软件和???应用软件??? 软件三个层次。…

django07 字符串替换

1. 模板语言&#xff08;字符串替换&#xff09; 1. 母版和继承 1. 什么时候用母版&#xff1f; html页面有重复的代码&#xff0c;把它们提取出来放到一个单独的html文件。 &#xff08;比如&#xff1a;导航条和左侧菜单&#xff09; 2. 子页面如何使用母版&#xff1f; {% e…

【云和恩墨】一次 truncate 核心表衍生的安全管理思考

第一章 一次 truncate 核心表衍生的安全管理思考 云和恩墨 | 2016-05-06 17:56 本文编辑整理来自上周四晚云和恩墨大讲堂 黄嵩 关于数据安全问题的分享。安全问题涉及到信息系统的方方面面&#xff0c;尤其是其核心资产——数据的安全。无论是数据访问控制的裸露&#xff0…

合理估算线程池线程数量

参考《Java并发编程实战》 线程数量计算公式 公式&#xff1a;Nthread Ncpu * Ucpu * &#xff08;1 W/C&#xff09;&#xff0c;各字段含义&#xff1a; Nthreads&#xff1a;线程数量 Ncpu&#xff1a;CPU的数量&#xff0c;Runtime.getRuntime().availableProcessors()…

通过regedt查看计算机密码,win10系统通过注册表设置定时更换密码提醒的处理步骤...

有关win10系统通过注册表设置定时更换密码提醒的操作方法想必大家有所耳闻。但是能够对win10系统通过注册表设置定时更换密码提醒进行实际操作的人却不多。其实解决win10系统通过注册表设置定时更换密码提醒的问题也不是难事&#xff0c;小编这里提示两点&#xff1a; 1、首先在…

苏宁零售云 App 稳定保障实践

1. 背景 苏宁零售云目标T4-T6级市场的业务&#xff0c;定位更靠谱的智慧零售解决方案和零售服务集成商&#xff0c;实战式跨界赋能。苏宁易购TO C的经验丰富&#xff0c;相关的方案很完善&#xff0c;但是零售云TO B相关业务启动后&#xff0c;业务增长迅速&#xff0c;App相关…

小酌重构系列[8]——提取接口

前言 世间唯一“不变”的是“变化”本身&#xff0c;这句话同样适用于软件设计和开发。在软件系统中&#xff0c;模块&#xff08;类、方法&#xff09;应该依赖于抽象&#xff0c;而不应该依赖于实现。 当需求发生“变化”时&#xff0c;如果模块&#xff08;类、方法&#xf…

多线程并发编程需要注意虚假唤醒Spurious wakeup

虚假唤醒 Spurious wakeup 如果等待线程在没有通知被调用的情况下唤醒&#xff0c;则称为Spurious wakeup。 解决方案就是: 使用while条件判断&#xff0c;更好的方案是避免使用wait这种低级的API&#xff0c;而是使用高级的并发工具。 因为这些高级的并发工具都是经过无数…

高中计算机个人总结怎么写,毕业生自我总结范文

毕业生自我总结范文1时光飞逝&#xff0c;三年忙碌而充实的大学生活在一片有序的繁忙中将要过去了&#xff0c;回首过去三年&#xff0c;内心感慨万千。我是20xx年春参加电大机械班的学习&#xff0c;回顾这三年的电大学习之路&#xff0c;饱含了汗水和收获。总结是一面镜子&am…

python - 字符串的格式化输出

# -*- coding:utf-8 -*-project: jiaxyauthor: Jimmyfile: study_2_str.pyide: PyCharm Community Editiontime: 2018-11-01 15:12blog: https://www.cnblogs.com/gotesting/# 字符串s #空字符串# 1:字符串拼接# 1.1:字符串与字符串的拼接用 连接s_1 hellos_2 worlds_3 5…