图说:为什么Java中的字符串被定义为不可变的
8张图,看懂Java字符串的不变性
字符串,想必大家最熟悉不过了,通常我们在代码中有几种方式可以创建字符串,比如:String s = "Hollis";这时,其实会在堆内存中创建一个字符串对象,其中保存了一个字符数组,该数组中保存了字符串的内容。
上面的箭头可以理解为“存储他的引用”。
当我们在代码中连续创建两个相同的字符串的时候,其实会指向同一个对象。因为当一个字符串被被创建的时候,首先会去这个字符串池中查找,如果找到,直接返回对该字符串的引用。


但是,如果在程序中明确声明要新创建一个字符串的话是可以在堆上重新创建一个对象的。如String s = new String("Hollis")

接着,我们来看两个字符串中常用的操作:截取和连接会发生什么,是在原来的字符串对象上修改还是重新创建字符串呢?
字符串的连接。如String s1 = s.concat("Chuang");

字符串的截取。如String s1 = s.substring(0,2);

从上图中我们可以得到一个结论,那就是——字符串是不可变的,无论发生什么操作,一个已经创建好的字符串的内容不会被改变,对它的任何类似修改的操作其实都是新生成了一个字符串对象。
那么,为什么要定义出不可变对象呢?
缓存Hashcode
Java中经常会用到字符串的哈希码(hashcode)。例如,在HashMap中,字符串的不可变能保证其hashcode永远保持一致,这样就可以避免一些不必要的麻烦。这也就意味着每次在使用一个字符串的hashcode的时候不用重新计算一次,这样更加高效。
在String类中,有以下代码:private int hash;
以上代码中
hash变量中就保存了一个String对象的hashcode,因为String类不可变,所以一旦对象被创建,该hash值也无法改变。所以,每次想要使用该对象的hashcode的时候,直接返回即可。
使其他类的使用更加便利
在介绍这个内容之前,先看以下代码:

在上面的例子中,如果字符串可以被改变,那么以上用法将有可能违反Set的设计原则,因为Set要求其中的元素不可以重复。上面的代码只是为了简单说明该问题,其实String类中并没有value这个字段值。
安全性
String被广泛的使用在其他Java类中充当参数。比如网络连接、打开文件等操作。如果字符串可变,那么类似操作可能导致安全问题。因为某个方法在调用连接操作的时候,他认为会连接到某台机器,但是实际上并没有(其他引用同一String对象的值修改会导致该连接中的字符串内容被修改)。可变的字符串也可能导致反射的安全问题,因为他的参数也是字符串。

不可变对象天生就是线程安全的
因为不可变对象不能被改变,所以他们可以自由地在多个线程之间共享。不需要任何同步处理。
总之,String被设计成不可变的主要目的是为了安全和高效。所以,使String是一个不可变类是一个很好的设计。
我的Java学习交流群:589809992 禁止闲聊,非喜勿进!
图说:为什么Java中的字符串被定义为不可变的的更多相关文章
- java中,字符串类型的时间数据怎样转换成date类型。
将字符串类型的时间转换成date类型可以使用SimpleDateFormat来转换,具体方法如下:1.定义一个字符串类型的时间:2.创建一个SimpleDateFormat对象并设置格式:3.最后使用 ...
- [原创]Java中的字符串比较,按照使用习惯进行比较
java中的字符串比较一般可以采用compareTo函数,如果a.compareTo(b)返回的是小于0的数,那么说明a的unicode编码值小于b的unicode编码值. 但是很多情况下,我们开发一 ...
- JAVA中关于数组的定义
前些日子,有网友问:在JAVA中 int[] a 这样定义的数组和 int a[] 定义的数组有什么区别? 当时没有细看,直接回复说,在JAVA中,两者是一样的,没有区别. 回头仔细看时,还是稍有区别 ...
- 理解Java中的字符串类型
1.Java内置对字符串的支持: 所谓的内置支持,即不用像C语言通过char指针实现字符串类型,并且Java的字符串编码是符合Unicode编码标准,这也意味着不用像C++那样通过使用string和w ...
- Java中的字符串驻留
转自:http://www.cdtarena.com/javapx/201307/9088.html 最近在工作的时候,一句再正常不过的代码String a = “hello” + “world”;被 ...
- Java中的字符串拼接
Java中的字符串拼接 1.设计源码 /** * @Title:IndexOf.java * @Package:com.you.freemarker.model * @Description: * @ ...
- Android学习笔记----Java中的字符串比较
用习惯了C#.C++,在做字符串比较时想当然地使用如下语句: string str1 = "abcd", str2 = "abcd"; if(str1==str ...
- 转载:Java中的字符串常量池详细介绍
引用自:http://blog.csdn.net/langhong8/article/details/50938041 这篇文章主要介绍了Java中的字符串常量池详细介绍,JVM为了减少字符串对象的重 ...
- 《Java入门第三季》第二章 认识 Java 中的字符串
什么是 Java 中的字符串.1.在Java的世界里,字符串被作为String类型的对象处理. 2.通用的初始化的方式:String s = new String("i love you & ...
随机推荐
- CTF---Web入门第八题 Guess Next Session
Guess Next Session分值:10 来源: iFurySt 难度:易 参与人数:3870人 Get Flag:1672人 答题人数:1690人 解题通过率:99% 写个算法没准就算出来了, ...
- Java学习之类的构建方法(函数)
在学习类的部分时,建立一个对象是这样建立的:(假设Person是类)Person p = new Person():我一直很费解为何new后面是一个函数形式, 今天学完构建方法后,才恍然大悟,豁然 ...
- Codeforces Round #328 (Div. 2)_B. The Monster and the Squirrel
B. The Monster and the Squirrel time limit per test 1 second memory limit per test 256 megabytes inp ...
- 整数n的全排列
第一道用搜索码的.得纪念一下 #include <iostream> #include <cstdio> #include <cstring> #include & ...
- 数据结构课程设计四则运算表达式求值(C语言版)
本系统为四则运算表达式求值系统,用于带小括号的一定范围内正负数的四则运算标准(中缀)表达式的求值.注意事项: 1.请保证输入的四则表达式的合法性.输入的中缀表达式中只能含有英文符号"+ ...
- Spark算子--foreach和foreachPartition
转载请标明出处http://www.cnblogs.com/haozhengfei/p/6776fe93f754daf60d00d2cb509422a1.html foreach和foreachPar ...
- Oracle_where子句
Oracle_where子句 --1.查询员工名为'SMITH'的信息 select * from emp where ename = 'SMITH'; --2.查询在1980/12/17入职的员 ...
- destoon 默认广告位代码
<img src="http://www.testinstrument.cn/skin/default/jiurong/img/banner.png" alt="& ...
- 【编程技巧】ExtJs 设置GridPanel表格文本垂直居中
详细讲解见 http://blog.csdn.net/li396864285/article/details/9310983 以下是我改修的代码: { width:90, ...
- Linux文件
Linux文件类型 对于内核而言,所有打开的文件都是通过文件描述符引用(FD),文件描述符是一个非负整数,当打开现有问价或创建一个新文件时,内核向进程返回一个文件描述符. 按照惯例,shell把文件描 ...