Java字符串常量池

Java字符串常量池

public static void testStringSimple(){
    String s11 = "test1";   // 字符串存储到堆中的字符串常量池,不会重复存储
    String s12 = "test1";   // 在常量池中获得引用
    System.out.println(s11 == s12); // true 1
    // toString()的结果也是放入字符串常量池中
    // 常量与常量拼接的结果也在常量池中,原理是编译期优化,其中"test"、"1"不会放入常量池中
    String s2 = "test" + "1";
    System.out.println(s11 == s2); // true 2
    // 常量数值、常量引用也是编译器优化
    final int b = 1;
    String s21 = "test" + b;
    System.out.println(s21 == s11); // true 3
    // 拼接时只要有一个是变量,就放到堆中,原理是创建StringBuilder,append()两个次符串对象,调用toString()返回String
    int a = 1;
    String s3 = "test" + a;  // 存在堆中
    System.out.println(s11 == s3); // false 4
    // 拼接的结果调用intern()方法,主动将常量池中还没有的字符串对象放入池中,返回此对象的地址
    String s4 = s3.intern(); // 存在常量池中,并返回引用给s4
    System.out.println(s4 == s3); // false 5
    System.out.println(s4 == s11); // true 6
}

public static void testStringHard(){
    // 下面语句创建了两个对象:一个对象是new关键字在堆空间创建,另一个是创建字符串常量池中的对象
    String s1 = new String("ab");
    String s2 = "ab";
    System.out.println(s1 == s2); // false
    // 1. 拼接时创建StringBuilder 2. new String("a"),调用构造器时把常量池中的"a"传过来 3.常量池中的"a"
    // 4. new String("b"") 5.常量池中"b" 6. 在StringBuilder的toString方法中创建new String()并返回给引用变量
    // 此时(仅考虑创建s3)字符串常量池中没有"ab",StringBuilder的toString()方法的调用,没有在字符串常量池中生成"ab"
    String s3 = new String("a") + new String("b");
}

public static void testQuestion(){
    String s = new String("1"); // 指向堆
    // 调用之前,字符串常量池中已有"1",因此不会在常量池中创建新的字符串常量
    s.intern();
    String s2 = "1";  // 指向常量池
    System.out.println(s == s2); // jdk6 jdk7/8 均为false

    String s3 = new String("1") + new String("1"); // s3 指向堆空间对象,常量池中没有创建"11"
    // 在字符串常量池中创建"11"。在jdk6中,常量池中创建了一个新的对象,因此地址不同。
    // jdk7/8中,常量池中不创建新对象"11",而是创建了指向堆空间中字符串对象的地址的引用,
    s3.intern();
    // s4指向上一行代码执行时,在常量池中生成的"11"。对于jdk6来说,指向的是常量池中的对象。对于7/8来说,把引用赋值给s4,指向堆中的字符串"11"
    String s4 = "11";
    System.out.println(s3 == s4); // jdk6 false, jdk 7/8 true
}

Java字符串常量池_第1张图片

造成以上区别的原因:

  • jdk6及以前,字符串常量池在Perm Gen(永久代)中,也就是方法区中。
  • jdk7及以后,字符串常量池在堆中。因此字符串要么在堆中,要么在堆的字符串常量池中,为了节省空间(引用类型只占4byte),在常量池中存引用。

你可能感兴趣的:(Java,秋招,java)