String、StringBuffer、StringBuilder三者的异同?

  • String:不可变的字符序列;底层使用 final char value[] 存储
  • StringBuffer:可变的字符序列;线程安全的,效率低;底层使用 char value[] 存储
  • StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全,效率高;底层使用 char value[] 存储

代码演示

  1. public class StringBufferTest {
  2. public static void main(String[] args) {
  3. StringBuffer sb1=new StringBuffer("abc");
  4. sb1.setCharAt(0,'m');//将第一个字符a,替换成m
  5. System.out.println(sb1); //查看原来的StringBuffer对象的值,结果为“mbc”
  6. }
  7. }
  1. 源码分析1
  2. String str=new String();//char[] value = new char[0];
  3. String str1=new String("abc");//char[] value = new char[]{'a','b','c'};
  4. StringBuffer sb1=new StringBuffer();//char[] value = new char[16];
  5. System.out.println(sb2.length());// 0
  6. //查看StringBuffer空的构造器方法如下可知:底层创建了一个长度是16的数组。
  7. sb1.append('a');//value[0]='a';
  8. sb1.append('b');//value[1]='b';

21.StringBuff与StringBuilder - 图1

1、点进源码中的super(),可以看到创建了一个新的大小为 capacity(16个字符) 的数组.

21.StringBuff与StringBuilder - 图2

2、点进源码中的value,可以看到就是StringBuffer所继承的父类中的 char[] 数组.

21.StringBuff与StringBuilder - 图3

  1. 源码分析2:
  2. StringBuffer sb2=new StringBuffer("abc"); //char[] value=new char["abc".length()+16];
  3. System.out.println(sb2.length());//16

21.StringBuff与StringBuilder - 图4

1、点进源码中的super(),可知所创建的数组的大小为所传入的 字符串的大小+16

21.StringBuff与StringBuilder - 图5

问题1:此时,System.out.println(sb2.length()) 结果为?;

答案:3,输出的为实际字符所占的长度。

问题2:扩容问题,初始的时候默认是16个字符,那要是添加的数据底层数组放不下了怎么办?

答案:扩容底层的数组。可以查看append()方法的源码可知。

默认情况下,扩容为原来的2倍 + 2,同时将原有数组中的元素复制到新的数组中。

1、其调用的是父类的append()方法。
21.StringBuff与StringBuilder - 图6

2、进入父类的append()方法可知,它首先判断是否为空,不为空则获取所要添加的参数的长度,然后判断数组容量是否足够(ensureCapacityInternal(count + len))
21.StringBuff与StringBuilder - 图7

3、进入ensureCapacityInternal方法,如果所需要的容量(minimumCapacity)大于当前数组的容量(value.length),则将当前数组的数据拷贝到新的数组当中 newCapacity(minimumCapacity)方法

21.StringBuff与StringBuilder - 图8

4、进入拷贝到的新数组newCapacity方法,它首先将当前的数组容量乘以2倍再加2,然后继续判断新的数组容量是否大于所需容量,如果大于,则返回生成新的数组大小为原来数组大小的2倍加2,如果仍然小于所需容量,则将所需容量当做新数组的容量大小。

21.StringBuff与StringBuilder - 图9

当开发当中经常要进行要进行扩容的操作,建议使用构造器:StringBuffer(int capacity) 构造器,指定数组容量,避免进行底层复制数组从而影响效率。

StringBuffer常用方法

21.StringBuff与StringBuilder - 图10

21.StringBuff与StringBuilder - 图11

StringBuilder类和StringBuffer类一样,只不过StringBuilder类没有同步方法,线程不安全,但效率比StringBuffer高

面试题:以下程序的输出结果

  1. String str=null;
  2. StringBuffer sb=new StringBuffer();
  3. sb.append(str);
  4. System.out.println(sb.length());//输出:4
  5. System.out.println(sb);//输出:"null" (带引号的null )
  6. StringBuffer sb1=new StringBuffer(str); //空指针异常
  7. System.out.println(sb1);

源码解析

1、进入append(String str)方法可知,如果传进来的参数为null,则执行super.append(str)方法
21.StringBuff与StringBuilder - 图12

2、进入super.append(str)方法k可知,会执行appendNull()方法
21.StringBuff与StringBuilder - 图13

3、进入appendNull()方法方法即可知道,会将null变为字符添加到char value[]当中,所以显示的长度为4,输出的结果为带引号的null

21.StringBuff与StringBuilder - 图14

4、进入StringBuffer(str)构造器,可知会执行str.length()判断传入参数的长度,此时会产生空指针异常,因为传入的str为null
21.StringBuff与StringBuilder - 图15