String str = "Hello, world!";
当我们创建String对象时,实际上时在堆内存中的字符串串池(String Table)中先检查是否有相同的数据,如果没有就会记录在子串池中,而str实际上记录的是串池中对应数据的地址值,所以无法直接修改其内容
String str = new String("Hello world!");
而new出来的对象不会在串池中而是在堆内存中重新开辟出来一个空间并传递回去其地址值,也是无法修改的
在JDK7以前这个串池是存放于方法区中的,但在JDK8时字符串串池被存放于了堆内存中
一:从运行过程中看
public class Main {
public static void main(String[] args) {
String str1 = "字符串";
String str2 = "字符串";
boolean flag = str1 == str2;
System.out.println(flag);
}
}
在这个代码中由于str1首先在堆内存的字符串串池中创建了“字符串”这个字符串对象,假设其地址为0x0011,那么传递给str1的数据其实为0x0011的地址值,而非“字符串”这个数据
那么当创建str2这个新的字符串对象时,会首先在串池中检索是否有这个“字符串”的数据,如果有就会返回这个数据的地址值给str2,即给str2赋值0x0011
所以在运行boolean flag str1==str2;时返回的结果为true
注:如果想要str1与str2中内容相同而地址值不同可以采用如下方法
public class Main {
public static void main(String[] args) {
String str1 = "字符串";
String str2 = new String("字符串");
boolean flag = str1 == str2;
System.out.println(flag);
}
}
因为 str1是记录在串池中的地址值,而str2记录的是new出来的新对象的地址值,尽管二者都是存在与堆内存中但地址值是不相同的,但这样做会导致资源的浪费。
二:从底层代码中看
1:String类整体是由final修饰的意为最终的,是无法修改的,强调其不能有子类来继承来修改它。
2:String类是底层是由字符数组来存储信息的,但其数组是被final与private来修饰的,代表一个常量且私有的字符数组,是不能修改其本身的内容的
3:String类中没有提供对外的修改字符串的方法
三:那么我们如何来修改字符串呢?
由一二可知,字符串是不能修改的,所以我们通常是重新在创建一个该字符串的副本,并在创建时进行修改,简单来说就是重新new一个新的对象