String类问题答疑

String

Posted by Jay on June 27, 2019

String类问题答疑

1. String为什么不可变?

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0
    // ...
}

​ 首先String类声明为final,则该类不能被其他类继承;其次String底层存储数据的是char[]数组,该数组是final的,则String在构造时必须初始化char[]数组,使得char[] value变量不能再指向其他数组(value数组中的元素值还是可变的)。但即使char[] value声明为final,其值也是可以改变的,比如通过反射。

真正使得String不可变的原因是①String类中的方法都是返回新的String对象,没有对原char[] value进行更改(copy);②没有暴露内部成员字段,没有暴露方法去修改;③String设计成final,禁止继承,避免被其他类继承后破坏。所以String是不可变的关键都在底层的实现,而不是一个final。考验的是JDK工程师构造数据类型,封装数据的功力。

2. hashCode()方法计算hash值时,为什么基数是31?

3. String.intern()方法作用

​ String常量池的主要使用方法有两种:

  • 直接使用双引号声明出来的String对象会直接存储在常量池中。

  • 如果不是用双引号声明的String对象(new出来的,存放在堆中),可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。

    JDK:

    “如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回”。

参考: 深入解析String#intern

4. 字符串对象创建个数问题

(1)

private static void test01() {

    String str1 = new String("A" + "B"); // 会创建多少个对象? 总共2,常量池1--"AB",堆内存1--new String("AB")
    
    String str2 = new String("ABC") + "ABC"; // 会创建多少个对象? 总共常量池1--"ABC",堆内存3--new String("ABC")/new StringBuilder()/StringBuilder.toString()
    
}

(2)

private static void test01() {

    String str = "hello";
    String str2 = "hel" + "lo"; // 这个是在编译的时候确定的,会在字符串常量池中创建一个hello对象,然后把对象的引用给str。
    System.out.println(str == str2); // true
    System.out.println(str.equals(str2)); // 始终比较的是值是否相等返回 true

    String str3 = "hel" + new String("lo"); // 运行时创建,在堆内存
    System.out.println(str == str3); // false
    System.out.println(str.equals(str3)); // true

    String str4 = new String("hello"); // new String("llo");这个是在运行的时候确定,所以这个会在堆中的字符创非常量池中去创建一个hello,返回引用,此时str == str3返回的就是false。
    System.out.println(str == str4); // false。在堆中存放的对象,只要有new就会是新的创建对象
    System.out.println(str.equals(str4));//true

    String str5 = "hel" + new String("lo"); // 有new就是新的
    String str6 = "hel" + new String("lo"); // 虽然这两个都是在堆的非常量池中动态创建,但是都是动态的,new String()所以不是使用同一份。
    System.out.println(str5 == str6); // false
    System.out.println(str5.equals(str6)); // true

    String str7 = new String("hello"); // 有new就是新的
    String str8 = new String("hello"); // 虽然这两个都是在堆的非常量池中动态创建,但是都是动态的,new String()所以不是使用同一份。
    System.out.println(str7 == str8); // false
    System.out.println(str7.equals(str8)); // true
}

(3)

String s=new String(str)+new String("ing") // 总共6个对象
// 常量池2个:"str" 和 "ing"
// 堆内存:2个String对象+1个StringBuilder对象+1个StringBuilder.toString()生成的String对象  

参考:请问下题中创建几个String对象?

参考文献