理清java字符串常量池

Java7后,字符串常量池从方法区移入堆中,同时String的intern()方法也从复制更改为了引用。

本文实例基于JRE1.8

1. 直接在字符串常量池生成,相等


@Test
public void test1() {
// 使用""构造的字符串,直接在字符串常量池生成
String str1 = "abcd";
String str2 = "ab" + "cd";
final String ab = "ab";
final String cd = "cd";
String str3 = ab + cd;
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str3 == str3);
// 运行结果
// true
// true
// true
}
 

使用idea查看其源代码,可知道编译器会对“”字符串进行优化,如下

    @Test
    public void test1() {
        String str1 = "abcd";
        String str2 = "abcd";
        String ab = "ab";
        String cd = "cd";
        String str3 = "abcd";
        System.out.println(str1 == str2);
        System.out.println(str1 == str3);
        System.out.println(str3 == str3);
    }

 

2. 特殊的String类

根据源码注释,我们可知:

  • 构造方法,构造方法先去字符串常量池判断是否存在,不存在创建,然后会在堆中创建一个拷贝(copy),也就是说引用的是堆中的拷贝;
  • intern()方法,先去字符串常量池判断是否存在,不存在在字符串常量池保存其堆中的引用,然后返回常量池中的对象;
    @Test
    public void test2() {
// new String()引用的是堆中的拷贝,因此与字符串常量池不相等,inert()也不会指向对于的堆中 String str1
= new String("abcd"); String str2 = str1.intern(); String str3 = "abcd"; System.out.println(str1 == str2); System.out.println(str1 == str3); System.out.println(str2 == str3); // 运行结果 // false // false // true }

    @Test
public void test3() {
// 使用StringBuilder、+=、new String() + 等直接在堆中生成,其对于的字符串若第一次调用intern()方法,会直接在字符串常量池保存其引用
// StringBuilder sb = new StringBuilder();
// sb.append("ab").append("cd");
// String str1 = sb.toString();
// String str1 = "ab";
// str1 += "cd";
String str1 = new String("ab") + new String("cd");
String str2 = str1.intern();
String str3 = "abcd";
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str2 == str3);
// 运行结果
// true
// true
// true
}

@Test
public void test4() {
// 更换位置,使得先在字符串常量池中生成"abcd",那么intern()只会返回值,而不是指向堆中再返回
String str1 = new String("ab") + new String("cd");
String str3 = "abcd";
String str2 = str1.intern();
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str2 == str3);
// 运行结果
// false
// false
// true
}

 

3. 总结时间

  • 从字符串常量池中获取的,都相等,如String str = "abcd"、str.intern()等;
  • 从堆中获取的,都不相等,如new String()、StringBuild.toString()、+=等;
  • 特殊情况,从堆中获取的,若其对于的字符串第一次调用intern()方法,那么后续从字符串常量池获取的都与他相等(new String("abcd")除外,他先在字符串常量池创建,然后在堆中创建副本); 

 

posted @ 2020-07-12 10:27  月華  阅读(170)  评论(0编辑  收藏  举报