String、StringBuffer、StringBuilder三者的异同?
- String:不可变的字符序列;底层使用 final char value[] 存储
- StringBuffer:可变的字符序列;线程安全的,效率低;底层使用 char value[] 存储
- StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全,效率高;底层使用 char value[] 存储
代码演示
public class StringBufferTest {
public static void main(String[] args) {
StringBuffer sb1=new StringBuffer("abc");
sb1.setCharAt(0,'m');//将第一个字符a,替换成m
System.out.println(sb1); //查看原来的StringBuffer对象的值,结果为“mbc”
}
}
源码分析1:
String str=new String();//char[] value = new char[0];
String str1=new String("abc");//char[] value = new char[]{'a','b','c'};
StringBuffer sb1=new StringBuffer();//char[] value = new char[16];
System.out.println(sb2.length());// 0
//查看StringBuffer空的构造器方法如下可知:底层创建了一个长度是16的数组。
sb1.append('a');//value[0]='a';
sb1.append('b');//value[1]='b';
1、点进源码中的super(),可以看到创建了一个新的大小为 capacity(16个字符) 的数组.
2、点进源码中的value,可以看到就是StringBuffer所继承的父类中的 char[] 数组.
源码分析2:
StringBuffer sb2=new StringBuffer("abc"); //char[] value=new char["abc".length()+16];
System.out.println(sb2.length());//16
1、点进源码中的super(),可知所创建的数组的大小为所传入的 字符串的大小+16
问题1:此时,System.out.println(sb2.length()) 结果为?;
答案:3,输出的为实际字符所占的长度。
问题2:扩容问题,初始的时候默认是16个字符,那要是添加的数据底层数组放不下了怎么办?
答案:扩容底层的数组。可以查看append()方法的源码可知。
默认情况下,扩容为原来的2倍 + 2,同时将原有数组中的元素复制到新的数组中。
1、其调用的是父类的append()方法。
2、进入父类的append()方法可知,它首先判断是否为空,不为空则获取所要添加的参数的长度,然后判断数组容量是否足够(ensureCapacityInternal(count + len))
3、进入ensureCapacityInternal方法,如果所需要的容量(minimumCapacity)大于当前数组的容量(value.length),则将当前数组的数据拷贝到新的数组当中 newCapacity(minimumCapacity)方法
4、进入拷贝到的新数组newCapacity方法,它首先将当前的数组容量乘以2倍再加2,然后继续判断新的数组容量是否大于所需容量,如果大于,则返回生成新的数组大小为原来数组大小的2倍加2,如果仍然小于所需容量,则将所需容量当做新数组的容量大小。
当开发当中经常要进行要进行扩容的操作,建议使用构造器:StringBuffer(int capacity) 构造器,指定数组容量,避免进行底层复制数组从而影响效率。
StringBuffer常用方法
StringBuilder类和StringBuffer类一样,只不过StringBuilder类没有同步方法,线程不安全,但效率比StringBuffer高
面试题:以下程序的输出结果
String str=null;
StringBuffer sb=new StringBuffer();
sb.append(str);
System.out.println(sb.length());//输出:4
System.out.println(sb);//输出:"null" (带引号的null )
StringBuffer sb1=new StringBuffer(str); //空指针异常
System.out.println(sb1);
源码解析
1、进入append(String str)方法可知,如果传进来的参数为null,则执行super.append(str)方法
2、进入super.append(str)方法k可知,会执行appendNull()方法
3、进入appendNull()方法方法即可知道,会将null变为字符添加到char value[]当中,所以显示的长度为4,输出的结果为带引号的null
4、进入StringBuffer(str)构造器,可知会执行str.length()判断传入参数的长度,此时会产生空指针异常,因为传入的str为null