String是一个Final类, 一旦赋值之后,就不能再修改了, 但平时编码时经常会遇到对String对象修改的情况, 那就只有一种解释:
平时对String的值的每次修改都是创建了一个新的String对象 ,并将引用指向了这个新的对象 .
因为String的值永远不会变,那么多处引用如果存储同一个字符串就没有必要为这一个不会变的字符串分配多份存储空间,可以推测出, 所有同一个值的引用最终指向的都是一块存储空间. 查询JVM规范之后,证实了这一点:
-
Literal strings within the same class (§8 (Classes)) in the same package (§7 (Packages)) represent references to the same
String
object (§4.3.1). -
Literal strings within different classes in the same package represent references to the same
String
object. -
Literal strings within different classes in different packages likewise represent references to the same
String
object.
参考链接: Oracle官方文档JDK8 https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5
String的值到底存在哪呢? 根据以上文档5.1章节, 可以知道应该是在运行时常量池中,运行时常量池属于方法区, JVM结构如下图:
方法区是由所有线程共享的数据区.下面用代码来验证一下这一点:
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
String str1="abc";
String str2="abc";
String str3=new String("abc");
System.out.println(str1==str2);
System.out.println(str1==str3);
Class str3Clazz=str3.getClass();
Field field=str3Clazz.getDeclaredField("value");
field.setAccessible(true);
char[] str3Chars= (char[]) field.get(str3);
str3Chars[0]='b';
System.out.println(str1+" "+str2+" "+str3);
}
此处的输出结果为:
true
false
bbc bbc bbc
用反射来验证的思路参考于: https://blog.csdn.net/qq_36418435/article/details/81623756