String与常量池

114 阅读2分钟

常量池

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);
  1. str1的"abc"先会在stringtable里找一圈。如果没有。
  2. 在字符串常量池中新建一个对象,由StringTable中形成一条记录,引用该对象的地址。双引号创建的String对象只会有一次。
String str11 = "abc";
System.out.println(str1 == str11);

str1用双引号引起来的字符串值在编译时存放在class常量池中。

  1. 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");\