例如下列代码
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
sout(str1==str2);
sout(str1==str3);
结果为true和false,原因是因为,str1和str2是直接赋值,当str1赋值时,会优先检查串池中是否存在abc字符串,若存在则之直接将串池中的地址赋值给str1,若不存在则在串池中生成对应的空间来保存该字符串,这样当str2进行赋值为abc时,会优先将串池中的该字符串的地址赋值给str2,这样str1和str2进行比较地址时,就发现地址相同,所以为true,而str3是使用new创建的字符串,这样就会在堆中创建一个新的字符串对象来保存该字符,这样str3中保存的地址是堆中的地址,所以进行比较的时候就不相同,所以为false。
总结来说:直接赋值,会复制字符串常量池中的内容,new出来的不会复用,而是开辟一个新的空间,==号对于引用数据类型来说比较的是地址值。
1.2 String类的数据拼接String str = "a"+"b"+"c";
上诉代码进行字符串拼接未出现变量,在jvm编译的形成class文件的时候实际上就相当于:
String str = "abc"
所以上述的字符串是属于串池管理
String str = "abc"; String str1 = str + "def";
上诉代码进行字符串拼接的时候,含有变量,则拼接的原理是首先在堆中创建一个StringBuilder对象,这里命名为sb,然后通过StringBuilder对象的append方法将str添加进sb,而后在使用append方法将def字符串也添加进sb中,最后在调用toString方法,将sb转为String类型返回,这样就会额外的创建了两个对象。如果上诉的拼接过程出现多次,就会产生大量的StringBuilde和String类型的对象,大大的降低了效率。
2. StringBuilder 2. 1StringBuilder的实现原理 StringBuilder的实现过程是首先创建一个默认容量为16字节的数组,当添加的内容的长度小于16时,直接添加,当添加的内容大于16时,进行扩容,扩容的方法为:原来的容量*2+2.
StringBuilder sb = new StringBuilder(); sout(sb.length); sout(sb.capacity());
上述代码执行的结果为:0 16 这是因为刚刚创建的StringBuilder对象,里面的内容为空,所以长度为0,容量为初始值16
在StringBuilder类中提供了空参构造方法
public StringBuilder(){
super(16);
}
在AbstractStringBuilder类中
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
//通过上诉代码可以看出,StringBuilder默认创建一个容量为16字节的数组
2.2 StringBuilder实现字符串的拼接
StringBuilder中的append方法的实现分析
public StringBuilder append(String str) {
super.append(str);
return this;
}
//获取用户输入的值,然后调用super.append方法
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//首先判断传入的字符串是否为null,如果则调用appendNull方法
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
//会将null的值进行赋值,然后返回
//否则则会先计算输入的字符串的长度,然后加上原来的长度count,从而的到目前所需要的最小的容量,在调用ensureCapacityInternal方法
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
//在ensureCapacityInternal方法中会判断所需要的最小的空间容量减去原来的空间容量,来确定是否能够装下,如果能够装下,则条件判断不成立,就不进行扩容,否则则进行扩容,最后将字符串添加进数组,然后修改数组的长度即可。
总结来说:使用StringBuilder来进行字符串的拼接效率比String的效率大大提高,其原理就是因为String需要开辟大量的空间,而StringBuilder则是使用数组来完成拼接的操作,不需要开辟额外的空间,StringBuilder的空间范围为int的最大值。这一点在JavaScript中可以类比,使用数组完成字符串拼接,效率更高。



