我们想知道为什么字符串是不可变的,就要先理解字符串的概念
字符串在存储上类似字符数组,所以它每一位的单个元素都是可以提取的,如s=“abcdefghij”,则s[0]=“a”。
为什么字符串是不可变的
上文我们可以知道字符串类似字符数组,既然是数组,我们就很容易想到数组在内存中的存储是连续的,即在定义数组时就分配了固定的地址和空间大小,那么字符串自然是不可变的。
1.前提条件?
字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。
2.字符串在内存中的存储
String a1 = "abc"; //字面量对象
String a2 = new String (abc); //构造对象
String a3 = a1;
我们通过String创建对象a1,a2,a3,
a1存放的是abc这个值的地址,a1放在栈里边,对象a1指向abc的地址。
a1的值,放在字符串常量池中,而字符串常量池是堆中的一个特殊区域(这里解释一下jdk1.7才把字符串常量池放到堆里)。
a2是通过new一个对象创建的,它是在堆中另开辟一个新空间,JVM首先会对这个字面量(abc)进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池。
由于a1已经使字符串常量池中存在了abc,所以a2在堆中开辟的空间用来存储字符串常量池中abc的地址。
对a3来说,就是a3只拷贝了a1的地址,并没有拷贝a1的值,和上面所述的概念原理一样,大家可以输出a3.equals(a1)来进行检查就知道了。
逻辑如图:
3.原因总结
- 字符串本质是数组,数组在创建时就开辟了一个连续地址,固定的空间的内存
- 字符串常量池实现的前提条件是Java中String对象是不可变的,字符串的值存放在字符串常量池中。
字符串不可变有一个优点就是编译器jet让字符串共享(字符串常量池),并且Java设计者认为共享带来的高效率远胜于提取、拼接字符串所带来的低效率。