点击关注公众号,Java干货及时送达

String的不变性

String在Java中特别常用,相信很多人都看过他的源码,在JDK中,关于String的类声明是这样的:

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
}

可以看到,String类是final类型的,那么也就是说,String是一个不可变对象。

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

可是有人会有疑惑,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.

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

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

缓存

字符串是使用最广泛的数据结构。大量的字符串的创建是非常耗费资源的,所以,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语言设计人员将该类设置为不可变类的其他原因。主要考虑的是缓存、安全性、线程安全和性能等方面

热门内容:拜托!不要用“ ! = null " 做判空了
道友自诉:入职中软一个月(外包华为)就离职了!
23 种设计模式的通俗解释,看完秒懂
token多平台身份认证架构设计思路
最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

明天见(。・ω・。)ノ♡

如何给女朋友解释为什么Java里面的String对象是不可变的?相关推荐

  1. 关于Java里面的String.getBytes()方法

    关于Java里面的String.getBytes()方法 Java里面的String类型的编码方式是Unicode,根据你项目字符串的编码方式无关,这是写死的.但是如果你jvm平台使用的是GBK编码方 ...

  2. java里面的string类型,java中的String类型(不知道理解的好不,请教大神)

    当执行String a = "abc"; 时候(前提条件是:执行这行代码之前在常量池中没有abc,若有,a直接引用在常量池中abc不在创建一个对象,若无,执行下面的描述) java ...

  3. JAVA里面的int类型 和Integer类型,有什么不一样

    JAVA里面的int类型 和Integer类型,有什么不一样 原创 2013年09月04日 23:15:11 标签: java / 2120 编辑 删除 JAVA里面的int类型 和Integer类型 ...

  4. Simple java里面的paint(Graphics g)的理解

    以前写画图板时,总不理解什么时候要调用这个方法,老师说:你写了paint(g)方法后,在窗体改变时,就会调用,可是不太理解. 没写paint(g)的演示:画图板v1 1:绘制简单直线 2.执行最小化操 ...

  5. Java 中的 String 真的是不可变的吗

    转载自   Java 中的 String 真的是不可变的吗 我们都知道 Java 中的 String 类的设计是不可变的,来看下 String 类的源码. public final class Str ...

  6. Java中的String为什么是不可变的? -- String源码分析

    什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不 ...

  7. java里面的ture和false

    java里的ture和false不像c++中的bool型变量,在c++中ture和false都是有值的,分别为1和0,并且可以比较大小. 例如:(3>4)的值为0,(44)的值为1.所以(44) ...

  8. 漫话:如何给女朋友解释String对象是不可变的?

    String的不变性 String在Java中特别常用,相信很多人都看过他的源码,在JDK中,关于String的类声明是这样的: public final class String implement ...

  9. Java中的String类为什么不可变

    1.什么是不可变? java角度来讲就是说成final的. String不可变如下图: 假设给字符串s赋值为abcd,第二次重新赋值为abcdef,这时候并不是在原内存地址上修改数据,而是重新指向一个 ...

最新文章

  1. 最小费用最大流 ---- 2017icpc青岛现场赛 K Our Journey of Xian Ends (拆点控制原图点度 + 中间必经过的点设置成源点 + 起点设成汇点)
  2. Python-OpenCV学习--电脑外接摄像头实时采集FAST角点并显示
  3. 使用 Boost.MPI 的骨架和内容进行优化的示例
  4. java httpclient 关闭_java中使用httpclient如何关闭debug日志
  5. Pandas 文本数据方法 wrap( )
  6. oracle性能优化求生指南_Vue项目性能优化--实践指南,网上最全最详细
  7. Selenium处理Select控件
  8. nvm npm node
  9. 线性代数知识点总结之行列式
  10. 初学者之路——————对抗神经网络
  11. 计算机函数sumifs应用题型难,在SUMIFS函数语句中使用Vlookup时遇到问题
  12. Microsoft SQL Server Native Client(sqlncli.msi)的安装程序包
  13. 友善串口助手使用教程_友善串口调试助手怎么进行配置-友善串口调试助手使用教程...
  14. 如何写好一份数据分析报告
  15. 【5G/4G】NAS与AS层 完整性保护与加密算法系列文章
  16. PHP 记录访客的浏览信息
  17. 雷电2接口_USB、Type-C、雷电3都是怎么一回事?
  18. WinSetupFromUSB制作多系统U盘引导启动
  19. winfrom 实现条形码批量打印以及将条形码信息生成PDF文件
  20. 小程序baes64转普通格式

热门文章

  1. 状压DP Hiho-1044 状态压缩
  2. Java IO 4 : RandomAccessFile
  3. 【C#技术】一篇文章搞掂:Infragistics组件库
  4. iOS开发-自己定义重用机制给ScrollerView加入子视图
  5. 如何利用自组织竞争网络进行患者癌症发病预测
  6. 利用Use Case为系统行为建模(3)
  7. 首届腾讯数字安全创新大赛在京启动,挖掘新锐力量推动产业创新
  8. 给力!斩获 GitHub 14000 Star,两周创办开源公司获数百万美元融资
  9. 快速上手微软 “群策 MARO” 平台,打造简易的共享单车场景
  10. 强化学习:10种真实的奖励与惩罚应用