一.String不可变
先说两点:
-
final关键词修饰的类不可以被其他类继承,但是该类本身可以继承其他类。
-
final关键词修饰的引用数据类型的变量值为地址值,地址值不能改变,但是地址内的数据对象可以被改变。
String类定义:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {}
String成员变量:
/** The value is used for character storage. */ private final char value[];
这里的value[]数组被final修饰,初始化之后就不能再被更改。但是大家注意,我们这里说的value[]不可变,指的是value的引用地址不可变,但是value数组里面的数据元素其实是可变的。例如某个指向数组的final引用,它必须从此至终指向初始化时指向的数组,但是这个数组的内容完全可以改变。
虽然value指向的数组是可以改变的,但是String也没有提供相应的方法让我们去修改value指向的数组的元素。所以这是String的不可变特性。
二.String拼接流程
我们经常会使用这样的代码来拼接两个字符串:
public static void main(String[] args) {
String str = new String("Hello");
str += " World";
System.out.println(str);
}
事实上,这样的拼接流程不是由String来操作的,而是执行了以下四步操作:
-
先创建一个StringBuilder对象,并调用无参数的构造方法。
-
StringBuilder对象调用append方法,把str内部 “Hello” 拼接到内部。
-
StringBuilder对象再次调用append方法,把 " World" 拼接到内部。
-
最后StringBuilder对象调用toString方法,把拼接好的字符串传给str。
以上步骤转化成代码其实就是:
public static void main(String[] args) {
String str = new String("Hello");
StringBuilder sb = new StringBuilder();
sb.append(str);
sb.append(" World");//拼接字符串
str = sb.toString();
System.out.println(str); //输出Hello World
}
三.StringBuilder
上面我们说过,由于String中的字符数组被final修饰并且String类当中并没有提供修改数组的方法,所以String不可变。而在StringBuilder中的char数组并没有被final修饰并且提供了响应的方法让我们去修改value指向的数组的元素,这也是StringBuilder的字符串序列可变的原因。
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
}
所以,当使用String进行字符串拼接时,产生了很多被弃用的StringBuilder对象(垃圾),当垃圾太多时会出发GC,从而减慢执行的效率。而StringBuilder支持不用创建新的对象在自身对象上进行操作,所以执行效率大大提高。