最近,又有好几个小伙伴问我这个问题:“二哥,为什么 Java 的 String 要设计成不可变的啊?”说实话,这也是一道非常经典的面试题,面试官超喜欢问。我之前写过这方面的文章,现在读起来似乎不太满意,所以我决定再啰嗦最后一次,交出一份更满意的答卷,让小伙伴们在面试官面前更从容一些,更有底气一些。

关于不可变对象,还有这样一个小故事。Java 之父詹姆斯高司令曾在一次采访中被问及这样一个问题:“高司令,应该什么时候使用不可变对象啊?”你猜高司令怎么回答?

如有可能,我愿意任何时候都使用不可变对象。

这就是高司令的答案,那有的小伙伴可能不服,老人家会说中文,你瞎扯吧你。也对哈,那就上英文呗:

I would use an immutable whenever I can.

这下彻底被打服了吧?老人家还说,不可变有着非常强大的功能,比如说,缓存、安全性、高性能等等。

01、什么是不可变对象

不可变对象在创建后,它的内部状态会保持不变,这就意味着,一旦我们将一个对象分配给一个变量,就无法再通过任何方式更改对象的状态了。

关于不可变对象的更多信息,可以查看我之前写的另外一篇文章——这次要说不明白immutable类,我就怎么地,看完啥都明白了。你看,写系列文章的好处就是这样,不需要重复造轮子,用到的时候直接搬出来套上就行了。

02、为什么 String 是不可变的

重点来了啊,为什么 String 是不可变的?原因可以从四个方面说起,缓存、安全性、同步和高性能。

1)字符串常量池

字符串恐怕是 Java 中最常用的数据形式了,如果字符串非要谦虚地说自己是老二,就没有人敢说自己是老大。

因此,把字符串缓存起来,并且重复使用它们会节省大量堆空间(堆内存用来存储 Java 中的对象,无论是成员变量、局部变量,还是类变量,它们指向的对象都存储在堆内存中),因为不同的字符串变量引用的是字符串常量池中的同一个对象。这也正是字符串常量池存在的目的。

字符串常量池是 Java 虚拟机用来存储字符串的一个特殊的区域,由于字符串是不可变的,因此 Java 虚拟机可以在字符串常量池中只为同一个字符串存储一个字符串副本来节省空间。

字符串常量池的主要使用方法有两种:

  • 直接使用双引号声明出来的字符串对象会直接存储在常量池中。
  • 否则,可以使用 String 类提供的 intern() 方法强制将当前字符串放入常量池中——常量池中查询不到当前字符串。

来看下面这段代码:

String 

由于字符串常量池的存在,所以两个不同的变量都指向了池中同一个字符串对象,从而节省了稀缺的内存资源。如果是通过 new 关键字创建的对象,则需要新的堆空间。

放心,关于字符串常量池,后面有时间的话,我再单独写一篇文章详细地说一说。

2)安全性

字符串在 Java 应用程序中的使用范围非常广,几乎无处不在,比如说存储用户名、密码、数据库连接地址等等这些非常敏感的信息,因此,必须要保证 String 类的绝对安全性。

来考虑一下下面这段代码:

void 

通常情况下,用户名由客户端传递到服务器端,服务器端接收后要先对用户名进行检查,再进行其他操作,因为客户端传递过来的信息不一定值得信任。

如果字符串是可变的,那么我们在执行 executeUpdate 更新数据库的时候,就有点不放心,因为即便是安全性检查通过了,字符串仍然有可能被修改。

在调用 isAlphaNumeric() 方法进行安全性检查期间,userName 的值仍然有可能被 criticalMethod() 方法的调用者进行篡改,就容易造成 SQL 注入。

但如果字符串是不可变的,这方面的担忧就不存在了。因为在执行更新之前,字符串的值是确定的,就是我们检查安全性之后的值。

3)线程安全

由于字符串是不可变的,因此可以在多线程之间共享,如果一个线程把字符串的值修改为另外一个,那么就会在字符串常量池中创建另外一个字符串,原有的字符串仍然会保持不变。

不过,很遗憾,我还不知道怎么从代码层面上去证明这一点,只能纯理论 yy 一下。小伙伴谁有办法的,教教我,在线等的那种。

4)哈希码

字符串广泛应用于 HashMap、HashTable、HashSet 等需要哈希码作为键的数据结构中,在对这些哈希表进行操作的时候,需要频繁调用 hashCode() 方法来获取键的哈希码。

public 

由于字符串是不可变性,这就保证了键值的哈希值不会发生改变,因此在第一次调用 String 类的 hashCode() 方法时,就对哈希值进行了缓存,此后,就一直返回相同的值。

/** Cache the hash code for the string */

由于哈希值被缓存了,这在另外一种层面上提高了哈希表的访问性能,因为哈希值不用重新计算了。

假如字符串是可变的,那就意味着哈希码会有多个,在通过键获取值的时候,就不一定能够获取到对的值了。

你看,字符串常量池的存在,哈希码的存在,在很大程度上提高了程序的性能。

03、总结

好了,我亲爱的小伙伴们,以上就是本文的全部内容了。我相信你一定对字符串的不可变性有了充足的了解,由于字符串是不可变的,因此我们可以将它看作是一个特殊的基本数据类型,哪怕是在多线程的环境下,也不用担心它的值是否会发生改变。

snmpset对象不可写_别再问了,好吗?Java字符串一定是不可变的相关推荐

  1. snmpset对象不可写_写 I/O 路径 (FTT1/RF2) 对比 – Nutanix vs VMware vSAN

    Josh博客原文 在这一部分中,我们将介绍每个产品写操作的I / O路径,这里的写操作是带镜像的(也称为vSAN的FTT1和Nutanix的RF2). 我将发布部署软件定义的存储"In-Ke ...

  2. snmpset对象不可写_[Python]可变对象与多进程通信

    一.可变对象与不可变对象 参考Python 的函数是怎么传递参数的? 具体看文档就行了,这里引用文章的结论: 1.对于不可变对象作为函数参数,相当于C系语言的值传递: 2.对于可变对象作为函数参数,相 ...

  3. feign post 传递空值_别再问 GET 和 POST 有什么不同了

    作用 GET 用于获取资源,而 POST 用于传输实体主体. 参数 GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体 ...

  4. 大三学生简历_不要再问那些没有的高级开发人员了。 开始指导大三学生。

    大三学生简历 by Ryan Bigg 通过瑞安·比格(Ryan Bigg) 不要再问那些没有的高级开发人员了. 开始指导大三学生. (Stop asking senior developers wh ...

  5. docker管理mysql风险_不要再问了,数据库不建议上Docker

    不要再问了,数据库不建议上Docker 前言 近2年Docker非常的火热,各位开发者恨不得把所有的应用.软件都部署在Docker容器中,但是您确定也要把数据库也部署的容器中吗? 这个问题不是子虚乌有 ...

  6. 最贵服务器多少钱_不要再问租用服务器一个月多少钱了?你看到的都是别人想给你看的...

    每一个想投身互联网浪潮的人都会先去了解服务器租用和托管的基础知识,因为无从下手,所以他们最喜欢搜的就是"租用服务器一个月多少钱""云服务器租用多少钱一个月"&q ...

  7. python docx run断开_别再问我python怎么操作Word了!

    原标题:别再问我python怎么操作Word了! 作者:陈熹 来源:早起Python 在之前的自动化系列文章中,我们分别讲解过python操作Excel利器openpyxl,也讲过python操作PD ...

  8. 拜托,学妹,别再问我怎么自学 Java 了!和盘托出

    假如有那么残酷的一天,我不小心喝错了一瓶药,一下子抹掉了我这十多年的编程经验,把我变成了一只小白.我想自学 Java,并且想要找到一份工作,我预计需要 6 个月的时间,前提条件是每天都处于高效率的学习 ...

  9. java怎么运行_不要再问我Java程序是怎么执行的了!

    什么是Java虚拟机? 要弄明白Java程序的执行过程首先要了解一下Java虚拟机. 虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的.Java虚拟机有自己完善的硬体架构 ...

最新文章

  1. 计算机科学基础知识(六)理解栈帧
  2. 什么叫碎片,碎片对io的影响以及什么叫物理顺序,什么叫逻辑
  3. SCCM2012之客户端发现与安装
  4. SQL Server 中关于 @@error 的一个小误区
  5. 以外的文件 删除_原来C盘还可以删除这五个文件,难怪电脑越来越卡!
  6. oracle大于当前月,oracle 现阶段年 当前月 当前周 当前日
  7. python -- join()
  8. mysql二进制安装方法
  9. mysql 5.7 延迟同步_完全解决 MySQL 5.7 主从复制的延迟问题
  10. DEV-C++官方下载地址
  11. QXDM 存储log的方法
  12. Language Models are Unsupervised Multitask Learners翻译
  13. Linpack安装、配置与运行
  14. leeCode350_两个数组的交集
  15. charles及弱网测试
  16. Bit.ly取代TinyURL成为Twitter默认网址缩写服务
  17. 携程的技术氛围怎么样?
  18. unity3d 九宫格切割以及如何获取切割完的图片
  19. CTF密码学-加解密总结
  20. 三国赵云传1---加血代码

热门文章

  1. Ubuntu中ssh远程报错:packet_write_wait: Connection to 192.168.163.190 port 22: Broken pipe lost connection
  2. Linux中 Vi的使用
  3. 定时让电脑进入休眠状态
  4. 力扣题目——103. 二叉树的锯齿形层序遍历
  5. 树莓派zero_w 串口的使用(解决usb可用rxtx不可用的问题)
  6. spring boot 全局异常处理的实现(@ExceptionHandler),以及@InitBinder、@ModelAttribute的作用
  7. springBoot JPA 数据库字段(实体类)带下划线在扩展findBy方法时出错的解决办法
  8. ubuntu命令行下中文乱码的解决方案
  9. 在sql中使用函数,遇到net.sf.jsqlparser.parser.ParseException异常
  10. 我可以在CSS中使用onclick效果吗?