String在Java中特别常用,而且我们经常要在代码中对字符串进行赋值和改变他的值,但是,为什么我们说字符串是不可变的呢?

首先,我们需要知道什么是不可变对象?

不可变对象是在完全创建后其内部状态保持不变的对象。这意味着,一旦对象被赋值给变量,我们既不能更新引用,也不能通过任何方式改变内部状态。

可是有人会有疑惑,String为什么不可变,我的代码中经常改变String的值啊,如下:

String s = "abcd";
s = s.concat("ef");

这样,操作,不就将原本的"abcd"的字符串改变成"abcdef"了么?

但是,虽然字符串内容看上去从"abcd"变成了"abcdef",但是实际上,我们得到的已经是一个新的字符串了。

如上图,在堆中重新创建了一个"abcdef"字符串,和"abcd"并不是同一个对象。

所以,一旦一个string对象在内存(堆)中被创建出来,他就无法被修改。而且,String类的所有方法都没有改变字符串本身的值,都是返回了一个新的对象。

如果我们想要一个可修改的字符串,可以选择StringBuffer 或者 StringBuilder这两个代替String。

为什么String要设计成不可变

在知道了"String是不可变"的之后,大家是不是一定都很疑惑:为什么要把String设计成不可变的呢?有什么好处呢?

这个问题,困扰过很多人,甚至有人直接问过Java的创始人James Gosling。

在一次采访中James Gosling被问到什么时候应该使用不可变变量,他给出的回答是:

I would use an immutable whenever I can.

那么,他给出这个答案背后的原因是什么呢?是基于哪些思考的呢?

其实,主要是从缓存、安全性、线程安全和性能等角度触发的。

Q:缓存、安全性、线程安全和性能?这有都是啥
A:你别急,听我一个一个给你讲就好了。

缓存

字符串是使用最广泛的数据结构。大量的字符串的创建是非常耗费资源的,所以,Java提供了对字符串的缓存功能,可以大大的节省堆空间。

JVM中专门开辟了一部分空间来存储Java字符串,那就是字符串池。

通过字符串池,两个内容相同的字符串变量,可以从池中指向同一个字符串对象,从而节省了关键的内存资源。

String s = "abcd";
String s2 = s;

对于这个例子,s和s2都表示"abcd",所以他们会指向字符串池中的同一个字符串对象:

但是,之所以可以这么做,主要是因为字符串的不变性。试想一下,如果字符串是可变的,我们一旦修改了s的内容,那必然导致s2的内容也被动的改变了,这显然不是我们想看到的。

安全性

字符串在Java应用程序中广泛用于存储敏感信息,如用户名、密码、连接url、网络连接等。JVM类加载器在加载类的时也广泛地使用它。

因此,保护String类对于提升整个应用程序的安全性至关重要。

当我们在程序中传递一个字符串的时候,如果这个字符串的内容是不可变的,那么我们就可以相信这个字符串中的内容。

但是,如果是可变的,那么这个字符串内容就可能随时都被修改。那么这个字符串内容就完全可信了。这样整个系统就没有安全性可言了。

线程安全

不可变会自动使字符串成为线程安全的,因为当从多个线程访问它们时,它们不会被更改。

因此,一般来说,不可变对象可以在同时运行的多个线程之间共享。它们也是线程安全的,因为如果线程更改了值,那么将在字符串池中创建一个新的字符串,而不是修改相同的值。因此,字符串对于多线程来说是安全的。

hashcode缓存

由于字符串对象被广泛地用作数据结构,它们也被广泛地用于哈希实现,如HashMap、HashTable、HashSet等。在对这些散列实现进行操作时,经常调用hashCode()方法。

不可变性保证了字符串的值不会改变。因此,hashCode()方法在String类中被重写,以方便缓存,这样在第一次hashCode()调用期间计算和缓存散列,并从那时起返回相同的值。

在String类中,有以下代码:

private int hash;//this is used to cache hash code

性能

前面提到了的字符串池、hashcode缓存等,都是提升性能的提现。

因为字符串不可变,所以可以用字符串池缓存,可以大大节省堆内存。而且还可以提前对hashcode进行缓存,更加高效

由于字符串是应用最广泛的数据结构,提高字符串的性能对提高整个应用程序的总体性能有相当大的影响。

总结

字符串是不可变的,因此它们的引用可以被视为普通变量,可以在方法之间和线程之间传递它们,而不必担心它所指向的实际字符串对象是否会改变。

我们还了解了促使Java语言设计人员将该类设置为不可变类的其他原因。主要考虑的是缓存、安全性、线程安全和性能等方面

Java 字符串的不可变性相关推荐

  1. 你真的理解Java 字符串的不可变性吗?

    作者:明明如月学长, CSDN 博客专家,蚂蚁集团高级 Java 工程师,<性能优化方法论>作者.<解锁大厂思维:剖析<阿里巴巴Java开发手册>>.<再学经 ...

  2. Java字符串的不可变性

    源码 在IDEA中找到,String的源码 // Java 11 public final class String implements Serializable, Comparable<St ...

  3. java 不可变性_Java字符串的不可变性

    简明现代魔法 -> Java编程语言 -> Java字符串的不可变性 Java字符串的不可变性 2009-11-08 String 对象是不可变的. 看似修改了 String 对象的方法, ...

  4. 深入理解字符串的不可变性[java]

    深入理解字符串的不可变性 /* 这篇文章是我认为写的最好的一篇文章,只要认真去看,我相信你一定会有收获 */ //只要你把其中的例题做对,也就代表你掌握了 首先,我们要探讨字符串的不可变性,那么究竟什 ...

  5. Java字符串就该这样设计

    一翻开Java面试题,基本上都会有考察字符串的不可变性,new String()和""的区别,字符串+内部实现等相关问题,您可能也知道常量池,看了一些堆栈图,了解了上述答案,可是过 ...

  6. java 常量字符串过长_90%的同学都没搞清楚的 Java 字符串常量池问题(图文并茂)

    字符串问题可谓是 Java 中经久不衰的问题,尤其是字符串常量池经常作为面试题出现.可即便是看似简单而又经常被提起的问题,还是有好多同学一知半解,看上去懂了,仔细分析起来却又发现不太明白. 背景说明 ...

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

    最近,又有好几个小伙伴问我这个问题:"二哥,为什么 Java 的 String 要设计成不可变的啊?"说实话,这也是一道非常经典的面试题,面试官超喜欢问.我之前写过这方面的文章,现 ...

  8. Java字符串的处理

    文章目录 本章学习要点 Java定义字符串(2种方式) 直接定义字符串 例 1 使用 String 类定义 1. String() 2. String(String original) 3. Stri ...

  9. 再见,Java字符串是不可变的

    最近,又有好几个小伙伴问我这个问题:"二哥,为什么 Java 的 String 要设计成不可变的啊?"说实话,这也是一道非常经典的面试题,面试官超喜欢问.我之前写过这方面的文章,现 ...

最新文章

  1. Ubuntu 11.04上搭建Android开发环境
  2. STM32 基础系列教程 40 - Lwip_mqtt
  3. Java 泛型中? super T和? extends T的区别
  4. Mckinsey insights 2
  5. AspectCore中的IoC容器和依赖注入
  6. android:paddingtop 百分比,相对层中的百分比宽度
  7. 第三次冲刺--软件工程
  8. Atian inputmethod 输入法解决方案 方言与多语言多文字支持 英语汉字汉语阿拉伯文的支持 (au
  9. html设置css字体样式表,HTML 学习笔记 CSS样式(字体)
  10. 近世代数——Part2 群:基础与子群
  11. 初级中学计算机知识,计算机基础知识(初级中学级教学方案课程教案).doc
  12. Java Web学习笔记 3 深入Servlet技术
  13. kindeditor默认粘贴为无文本格式怎么实现配置
  14. Qt数据库应用23-个人信息报表
  15. 偏财入财库大富_什么是八字有财库者大富
  16. 游戏建模师是做什么的?薪资高不高?
  17. 来,肝了这份网络安全学习计划无敌
  18. mac上最好用的在线视频播放器:IINA+ for Mac
  19. JAVA ffmpeg 视频处理
  20. 用Qt搭建图书管理系统 (十四)

热门文章

  1. 自动化测试平台化[v1.0.0][事件驱动理论]
  2. MCU死机查原因,Crash dump堆栈回溯技术轻松搞定
  3. 聊一聊 15.5K 的 FileSaver,是如何工作的?
  4. DES算法原理及其实现
  5. python中format函数作用_Python代码中format函数具有哪些功能呢?
  6. 求任意半径圆的面积c语言,需要一个输入半径求圆面积的C语言程序
  7. mbp安装mysql
  8. Spring中的循环依赖解决详解
  9. Flink SQL·validate
  10. 电脑使用变慢七大原因分析