String
Java提供了String类型来表示字符串
保存字符串的方式
String类中用来保存字符串的数据接口是一个byte[],并且用fianl修饰了这个数组。
private final byte[] value;
String类没有提供接口来修改字符串的值,所以String是不可以被修改的,而且是线程安全的。
创建字符串
创建字符串有两种方式:
- String str = “abc”。当使用这种方式创建字符串时,JVM会在堆内存中搜索看之前是否有用这种方式创建过"abc"字符串,如果有,就只直接返回让str引用已经存在的"abc"。如下代码实例中s1 == s2是true, s1 == s5是true
- String str = new String(“abc”)。当使用这种方式创建字符串时,JVM会直接从堆中开辟一块新的内存来创建这个对象。如下代码中s1 == s3 = false, s1 == s6 = false
代码实例
public class TestString {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
String s5 = "ab" + "c";
String s6 = "ab" + new String("c");
System.out.println("s1 == s2 = " + (s1 == s2));
System.out.println("s1 == s3 = " + (s1 == s3));
System.out.println("s3 == s4 = " + (s3 == s4));
System.out.println("s1 == s5 = " + (s1 == s5));
System.out.println("s1 == s6 = " + (s1 == s6));
System.out.println("s3 == s6 = " + (s3 == s6));
}
}
运行结果,因为String类型不能修改字符串。所以String s5 = “ab” + “c”;这句代码实际上会创建三个对象"ab", “c”, “abc”,在这段代码里因为前面已经有定义过String s1 = “abc”;"abc"已经被创建了,所以s5==s1。
s1 == s2 = true
s1 == s3 = false
s3 == s4 = false
s1 == s5 = true
s1 == s6 = false
s3 == s6 = false
Process finished with exit code 0
另外,String类是不可以被继承的,因为String类被final修饰了
StringBuilder和StringBuffer
JAVA还提供了两种可以修改字符串内容的类,他们都是AbstractStringBuilder的子类,并且都被final修饰,都是不可以被继承的,区别在于:
- StringBuffer: 线程安全
- StringBuilder:线程不安全
StringBuffer
StringBuffer是线程安全的,实现线程安全的方法是用synchronized关键字,可以看到StringBuffer的很多方法都被synchronized修饰了。
StringBuffer可以用appen()方法来拼接字符串,并且不会创建新的对象。
代码实例:
public class TestStringBuffer {
public static void main(String[] args) {
StringBuffer sb1 = new StringBuffer("a");
StringBuffer sb2 = sb1.append("b");
System.out.println(sb1 == sb2);
}
}
运行结果
true
Process finished with exit code 0
可以看一下源码中append是如何实现的:
public AbstractStringBuilder append(String str) {
if (str == null) {
return appendNull();
}
int len = str.length();
ensureCapacityInternal(count + len); // 检查是否需要扩容
putStringAt(count, str); // 将字符串填充到尾部
count += len;
return this;
}
private final void putStringAt(int index, String str) {
if (getCoder() != str.coder()) {
inflate();
}
str.getBytes(value, index, coder); // value是StringBuffer类中存字符串的数组
}
可以看到是通过调用String类的getBytes(str.getBytes(value, index, coder);)把str的内容拼接到StringBuffer后面
StringBuilder
StringBuilder是线程不安全的,除此自外跟StringBuffer没有很大的区别
代码实例:
public class TestStringBuilder {
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("a");
StringBuilder sb2 = sb1.append("b");
System.out.println(sb1 == sb2);
}
}
运行结果
true
Process finished with exit code 0