@JeromeLiee
2020-02-11T23:29:08.000000Z
字数 1933
阅读 467
java基础:String — 字符串常量池与intern(二)
String
是Java中的一个类,可以用来表示字符串,其内部使用 char
数组来存储数据。
public final class String {
/** The value is used for character storage. */
private final char value[];
...
}
其中内部存储数据的 char
数组使用 final
来修饰,并且没有提供可修改 char
数组的方法,则表明当 String
对象被创建后,其值是不可变的。
字符串常量池保存着所有字符串的字面量,这些字面量在编译期间就已经被确定。不过在运行期间,也可以通过String.intern()方法将一个字符串添加到常量池中。
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // 输出false
String s3 = s1.intern();
String s4 = s2.intern();
System.out.println(s3 == s4); // 输出true
在上述代码中,s1
指向了在堆中创建的一个String对象,s2
指向了在堆中创建的另外一个String对象,所以它们的地址值不相等,输出false;而接下来通过s1.intern()方法判断字符串"abc"
是否在常量池中,是则直接返回,否则创建并返回,所以s3、s4都指向了常量池中同一个"abc"字符串常量,所以输出为true。
String s1 = "abc";
StringBuilder s2 = new StringBuilder("abc");
System.out.println(s1 == s2); // 输出false
System.out.println(s1.equals(s2)); // 输出false
System.out.println(s1.contentEquals(s2)); // 输出false
第一行输出:因为二者为两个不同的对象,地址值不同,所以false;
第二行输出:因为在String的equals()方法中,会先判断二者类型是否相同,不同则为false,而s1和s2一个是String类型一个是StringBuilder类型,所以false;
第三行输出:因为在String的contenEquals()方法中会判断传入参数的类型,如果是StringBuffer或StringBuilder则比较其内部的char数组是否一致,所以输出为true。
String是不可变的,当对String类进行操作的时候,例如拼接等,总会创建新的String对象,比较消耗资源,所以Java提供了两个可以对String进行高效操作的可变工具类——StringBuffer和StringBuilder。
StringBuffer和StringBuilder内部维护了一个可变的char数组,在对字符串操作时,实质上是对这个可变char数组进行操作,在toString()方法会调用String的构造方法,将这个可变的char数组传递过去,创建一个新的String对象。
StringBuffer是线程安全的,因为在其每个操作方法上都加了synchronized
关键字,而StringBuilder没有加该关键字,所以是线程不安全的。
如果是常量、字面量以及基本数据类型变量通过“+” 符号连接的话,会直接被编译成字符串:
String s = "a" + "b" + 1;
// 等同于下面的代码
String a = "ab1";
而如果有String对象参与,则通过StringBuilder进行拼接:
String a = "a";
String b = a + "b" + 1;
// 等同于下面的代码
String a = "a";
StringBuilder builder = new StringBuilder();
String b =