常量池
3大常量池 静态常量池经过类加载后,都要在运行时常量池进行存储。字面量会加载到运行时常量池中。但双引号引起来的字符串值中会存储到字符串常量池。
1. class常量池|静态常量池
存储在.class文件里,1个.class文件只有1个class常量池
1.1 字面量 包含数值型:int、float、long、double等。以及双引号引起来的字符串值。
1.2 符号引用
2. 运行时常量池
jvm内存/运行时数据区中。
3. 字符串常量池
jvm内存/运行时数据区中,全局唯一。字符串常量池中,1.7以后存储在堆空间。字符串常量池设计的目的在于去重,为了更快的匹配某个字符串是否存在于常量池中,java在设计字符串常量池的时候,还搞了一张(stringtable),stringtable有点类似于我们的hashtable,里面保存了字符串的引用。
String在常量池中存储
在常量池中分为值和类型两部分进行存储。
1. 类型 CONSTANT_String_info
CONSTANT_String_info{
//u1 1个无符号字节
u1 tag=8;
//u2 2个无符号字节
u2 string_index;
}
1.1 【1字节】tag = 8
1.2 【两字节】string_index 索引,指向了某个CONSTANT_Utf8_info结构体。
2. 数据 CONSTANT_Utf8_info
CONSTANT_Utf8_info{
u1 tag=1;
//表示这个utf8编码的字节数组的长度/表示多少个字节
u2 length;
//使用了utf-8编码后的字节数组
u1 bytes[length];
}
String创建对象相关问题
1. 双引号与new String()
String str1 = "abc";
String str2 = new String("abc");
System.out.println(str1 == str2);
- str1的"abc"先会在stringtable里找一圈。如果没有。
- 在字符串常量池中新建一个对象,由StringTable中形成一条记录,引用该对象的地址。双引号创建的String对象只会有一次。
String str11 = "abc";
System.out.println(str1 == str11);
str1用双引号引起来的字符串值在编译时存放在class常量池中。
- str2因为new了String对象,new会在堆空间的区域内创建对象。new一次就会新建一次。
String str3 = new String("abc");
System.out.println(str2 == str3);
2. 编译或运行时调用String相关方法
final String a = "a";//常量
String str5 = a + "b";
System.out.println(str5 == "ab");
String s1 = "a";
String s2 = "b";
String str6 = s1 + s2;//运行期间做字符串拼接都经过Stringbuffer
System.out.println(str6 == "ab");
String str7 = "abc".substring(0,2);//运行期间方法调用,都是一个new操作
System.out.println(str7 == "ab");
String str8 = "abc".toUpperCase();//运行期间方法调用,都是一个new操作
System.out.println(str8 == "ABC");\