Java学习之String、StringBuilder和StringBuffer

StringBuffer(JDK1.0)

1、相关知识

String源码分析

StringBuffer介绍:

1、线程安全的可变字符序列。一个类似于String的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。

2、可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。

3、每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量自动增大。

2、定义

 public final class StringBuffer
 	extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence

1、StringBuffer是final修饰的,所以不可以被继承。

2、继承了的AbstractStringBuilder类,这个类是StringBuilder和StringBuffer的直接父类,该类在源码中注释是以JDK1.5开始作为他们的父类,可是直到JDK1.8的API中,Object才是StringBuilder和StringBuffer的父类。

3、AbstractStringBuilder类实现了可变字符序列的一系列的操作,比如append()、insert()、delete()、replace()、charAt()方法等 。

4、Serializable接口:序列化接口,表示对象可以被序列化。

​ CharSequence接口:字符序列接口,提供了几个对字符序列进行只读访问的方法,比如:length()、charAt()、subSequence()、toString()方法等。

//构建一个StringBuffer的对象
StringBuffer stringBuffer = new StringBuffer("123");
//源码分析
private transient char[] toStringCache;
//被transient修饰的变量不会贯穿对象的序列化和反序列化,生命周期仅存于调用者的内存中而不会写到磁盘里进行持久化。假如一个用户有一些密码等信息,为了安全起见,不希望在网络操作中被传输,这些信息对应的变量就可以加上transient关键字。用来缓存toString()方法返回的最近一次的value数组中的字符。当修改StringBuffer对象时会被清除。

// 下面的两个变量是在AbstractStringBuilder.java中

char[] value;//用来存储字符序列中的字符。value是一个动态的数组,当存储容量不足时,会对它进行扩容。

int count;//表示value数组中已存储的字符数。
//……
public StringBuffer(String str) {
    
    
    super(str.length() + 16);//把字符串长度传给父类AbstractStringBuilder的构造方法
    append(str);
//构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。该字符串的初始容量为 16 加上字符串参数的长度。 
}
//……
//AbstractStringBuilder.java
AbstractStringBuilder(int capacity) {
    
    
    value = new char[capacity];//利用子类传来的字符串长度对value数组进行初始化
}
//StringBuffer提供了4种构造方法,我们选择了其中的一种,构造方法主要完成了对value数组的初始化。

3、append(String str)方法如何扩容

StringBuffer sb1 = new StringBuffer("123");
sb1 = sb1.append("456");
System.out.println(sb1);//输出:123456
//源码分析
@Override
public synchronized StringBuffer append(String str) {
    
    
    toStringCache = null;
    super.append(str);	//本质上是调用了父类AbstractStringBuilder类中对应的方法
    return this;
}


//下面的两个变量是在AbstractStringBuilder.java中
public AbstractStringBuilder append(String str) {
    
    
    if (str == null)						//如果传入的字符串为空
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);	  //判断value数组的容量是否足够
    str.getChars(0, len, value, count);		  //将str从此序列复制到目标字符数组value	  
    count += len;
    return this;
}

private AbstractStringBuilder appendNull() {
    
    //如果传入str为空
    int c = count;
    ensureCapacityInternal(c + 4);			 //判断value数组的容量是否足够
    final char[] value = this.value;		 //把null放入value数组
    value[c++] = 'n';
    value[c++] = 'u';
    value[c++] = 'l';
    value[c++] = 'l';
    count = c;
    return this;
}

public void ensureCapacity(int minimumCapacity) {
    
    	//首先内部先确认一遍传的参数是否有效
    if (minimumCapacity > 0)					   //即是否大于0
        ensureCapacityInternal(minimumCapacity);
}

private void ensureCapacityInternal(int minimumCapacity) {
    
    
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
    
    		//value数组的容量不足
        value = Arrays.copyOf(value,newCapacity(minimumCapacity));
        //调用newCapacity()方法进行扩容,再调用Arrays类的copyOf()静态方法来创建一个新数组并拷贝原数据到新数组,并将value指向新数组。
    }
}

private int newCapacity(int minCapacity) {
    
    
    // overflow-conscious code

    int newCapacity = (value.length << 1) + 2;//默认情况下将数组容量扩大到原数组容量的2倍+2
    if (newCapacity - minCapacity < 0) {
    
    
        newCapacity = minCapacity;
    }
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
    //新容量必需在int所支持的范围内,之所以有<=0判断是因为,在执行 (value.length << 1) + 2操作后,
    //可能会出现int溢出的情况。如果溢出或是大于所支持的最大容量(MAX_ARRAY_SIZE为int所支持的最	   	   //大值减8)就会调用hugeCapacity()方法进行计算,否则取newCapacity作为新容量
}

private int hugeCapacity(int minCapacity) {
    
    
    if (Integer.MAX_VALUE - minCapacity < 0) {
    
     // overflow
        throw new OutOfMemoryError();//数组的容量最大只能扩容到Integer.MAX_VALUE,如果最大容量都小于扩容后的容量的话,就会报内存溢出异常,即必须在int所支持的最大范围内。
    }
    return (minCapacity > MAX_ARRAY_SIZE)//范围是Integer.MAX_VALUE - 8到Integer.MAX_VALUE之间
        ? minCapacity : MAX_ARRAY_SIZE;	 //在minCapacity与MAX_ARRAY_SIZE之间取较大者
}

StringBuilder(JDK1.5)

StringBuffer介绍:

​ 一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。

StringBuffer和StringBuilder的区别:

1、线程安全性

​ StringBuffer是线程安全的,因为当StringBuffer对象在字符串缓冲区被多个线程使用时,很多方法因为带有synchronized关键字,所以可以保证多线程是同步执行的。

​ 但StringBuilder的方法中没有synchronized关键字,多线程不能同步执行,所以是线程不安全的。

2、性能

比较StringBuffer和StringBuilder使用append方法拼接字符串的性能

//StringBuffer
StringBuffer sb01 = new StringBuffer("123");
long startTime = System.currentTimeMillis();	//执行前时间(ms毫秒)
for (int i = 0 ; i < 100000000 ; i++)			//append一亿次
{
    
    
    sb01 = sb01.append("123");
}
long endTime = System.currentTimeMillis();		//执行结束的时间(ms毫秒)
System.out.println(endTime - startTime);		//执行使用的时间(ms毫秒)
//输出:2690	
//StringBuilder
StringBuilder sb01 = new StringBuilder("123");
long startTime = System.currentTimeMillis();//执行前时间(ms毫秒)
for (int i = 0 ; i < 100000000 ; i++)		//append一亿次
{
    
    	
    sb01 = sb01.append("123");
}
long endTime = System.currentTimeMillis();  //执行结束的时间(ms毫秒)
System.out.println(endTime - startTime);	//执行使用的时间(ms毫秒)
//输出:1166

通过这个测试得出性能:StringBuilder>StringBuffer

3、缓冲区

//StringBuffer
private transient char[] toStringCache;

@Override
public synchronized String toString() {
    
    
    if (toStringCache == null) {
    
    
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}
//StringBuilder
@Override
public String toString() {
    
    
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

StringBuffer调用tostring会直接使用缓冲区的toStringCache来构造一个字符串,是synchronized同步化的。

StringBuilder调用tostring会通过new一个String对象来构造一个字符串。

总结:

String:适用于少量字符串操作,通过隔离,还是可以使用

StringBuffer:因为线程安全,所以适用多线程下在字符缓冲区进行大量操作

StringBuilder:因为线程不安全,适用于单线程下在字符缓冲区进行大量操作,通过隔离,还是可以使用

希望可以和大家互相学习,谢谢大家!!!

猜你喜欢

转载自blog.csdn.net/qq_42039952/article/details/115383155