源码解剖|java源码解剖-字符串常量在内存中的保存方式

String类型的字符串是用char数组保存字符串的值的,
源码解剖|java源码解剖-字符串常量在内存中的保存方式
文章图片

即如图的String的源码定义,它是存在char字符数组中的,所以其equals方法的是比较char数组的每一位是否相同。并且它是final类型的,不可改变。
1、显示声明的字符串是存在常量池的。
因为显示地定义字符串如"abc",它是存在常量池里的,所以如下图
源码解剖|java源码解剖-字符串常量在内存中的保存方式
文章图片

对于a和a1均指向常量池中的“abc”。如下图所示:
源码解剖|java源码解剖-字符串常量在内存中的保存方式
文章图片

此处引入字符串驻留,当相同的字符串常量被多次创建(使用双引号显示声明)时,字符串常量对象会被创建在常量池中,且只会创建一个对象。
2、new出来的字符串存储。
源码解剖|java源码解剖-字符串常量在内存中的保存方式
文章图片

上边代码中的new字符串的过程:先将显示定义的字符串bcd存入常量池中,然后再在堆中创建一个bcd,并将s指向堆中的bcd。如下图,
源码解剖|java源码解剖-字符串常量在内存中的保存方式
文章图片

3、字符串的+

//定义1 String c = "hello"+"world"; //定义2 String d = "he"; String e = d+"llo"; //定义3 String f = new String("wor")+new String("ld");

三者JVM编译后的样子:
//定义1 String c = "helloworld"; //定义2 String d = "he"; String e = String.valueOf(d)+"llo"; //定义3 String f = new String("wor")+new String("ld");

定义1中c对象指向的是常量池中的“helloworld”。
定义2中String.valueOf中重新new了一个String对象,所以e指向堆内存中的“hello”。
定义3中f是在堆内存中定义了"world"。字符串的+号运算,会在堆内存中生成新的字符串对象。
写在后边的话
java7之前,保存字符串的常量的常量池在方法区(永久代)中。
java7开始,保存字符串的常量的常量池在堆中。
java7开始,intern,去常量池中寻找当前的字符串常量,如果有,那么直接返回常量池中的字符串对象,如果没有,那么会把当前的字符串常量的引用放入常量池,然后返回。
java7以前,intern,去常量池中寻找当前的字符串常量,如果有,那么直接返回常量池中的字符串对象,如果没有,那么会把当前字符串常量拷贝一个副本放入常量池中,并返回该常量。
源码解剖|java源码解剖-字符串常量在内存中的保存方式
文章图片


【源码解剖|java源码解剖-字符串常量在内存中的保存方式】


    推荐阅读