String类型的字符串是用char数组保存字符串的值的,
文章图片
即如图的String的源码定义,它是存在char字符数组中的,所以其equals方法的是比较char数组的每一位是否相同。并且它是final类型的,不可改变。
1、显示声明的字符串是存在常量池的。
因为显示地定义字符串如"abc",它是存在常量池里的,所以如下图
文章图片
对于a和a1均指向常量池中的“abc”。如下图所示:
文章图片
此处引入字符串驻留,当相同的字符串常量被多次创建(使用双引号显示声明)时,字符串常量对象会被创建在常量池中,且只会创建一个对象。
2、new出来的字符串存储。
文章图片
上边代码中的new字符串的过程:先将显示定义的字符串bcd存入常量池中,然后再在堆中创建一个bcd,并将s指向堆中的bcd。如下图,
文章图片
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源码解剖-字符串常量在内存中的保存方式】