本文是根据JDK1.8以及网上查阅资料分析总结的,如果有什么缺陷或者遗漏,欢迎指正,谢谢。
1. String
2. StringBuffer
2.1 为什么有StringBuffer
String对象一旦创建就不能更改,即使我们使用方法对其进行替换,实际上我们是重新创建了一个String 对象,原有对象依然存在。这一特点使得内存空间占用较多。
String做字符串拼接,既费时又耗内存,但这种拼接操作又是比较常见的。
为了解决这个问题,Java提供了StringBuffer类来实现字符串中内容的添加、修改和删除操作。
StringBuffer:就是字符串缓冲区,用于存储可变字符序列的容器。
特点:
(1) 可以对字符串进行修改。
(2) 长度可变。
2.2 StringBuffer的构造函数
类的声明:
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
StringBuffer类的构造方法有三个:
public StringBuffer() // 表示创建了一个空的StringBuffer对象,默认长度是 16
public StringBuffer(int length) // 表示创建了一个长度为length的StringBuffer对象
public StringBuffer(String str) // 表示创建了一个StringBuffer对象并用字符串str对其初始化,长度为 str.length() + 16
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
/**
* Constructs a string buffer with no characters in it and
* the specified initial capacity.
*
* @param capacity the initial capacity.
* @exception NegativeArraySizeException if the {@code capacity}
* argument is less than {@code 0}.
*/
public StringBuffer(int capacity) {
super(capacity);
}
/**
* Constructs a string buffer initialized to the contents of the
* specified string. The initial capacity of the string buffer is
* {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
*/
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
2.3 StringBuffer 常用方法
1. 添加 -- 接受的参数有很多类型,int long float double char boolean char[] CharSequence ...
public synchronized StringBuffer append(int i)
public synchronized StringBuffer insert(int offset, char c)
2. 删除 -- 删除方法就这两种
public synchronized StringBuffer deleteCharAt(int index)
public synchronized StringBuffer delete(int start, int end)
3. 查找
public synchronized char charAt(int index)
public int lastIndexOf(String str)
public synchronized int lastIndexOf(String str, int fromIndex)
4. 修改
public synchronized void setCharAt(int index, char ch)
public synchronized StringBuffer replace(int start, int end, String str)
. . .
3. StringBuilder
3.1 StringBuilder 介绍
StringBuilder是从JDK1.5版本开始出现的,作用于StringBuffer一样,唯一的区别在于线程同步上。
比较StringBuffer和StringBuilder的方法声明方式,StringBuffer里面的方法都有 synchronized 修饰,是线程安全的。所以StringBuffer支持并发操作,线性安全的,适合多线程中使用。
而StringBuilder不支持并发操作,是线性不安全的,不适合多线程中使用。虽然引入的StringBuilder类不是线程安全的,但其在单线程中的性能比 StringBuffer高。
String,StringBuilder,StringBuilder三者的执行速度比较:StringBuilder > StringBuffer > String
因为String是常量,不可变,效率最慢,StringBuffer和StringBuilder都是可变的字符序列,执行速度上要快于String。
StringBuffer是线程安全的,意味着要花费时间去维持线程安全性,而StringBuilder不用,所以StringBuilder执行速度要快于StringBuffer。
3.2 StringBuilder 的构造函数
类的声明:
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
StringBuilder类的构造方法有四个:
public StringBuilder() // 表示创建了一个空的StringBuilder对象,默认长度是 16
public StringBuilder(int length) // 表示创建了一个长度为length的StringBuilder对象
public StringBuilder(String str) // 表示创建了一个StringBuilder对象并用字符串str对其初始化,长度为 str.length() + 16
public StringBuilder(CharSequence seq) // 表示创建了一个StringBuilder对象并用字符序列seq对其初始化,长度为 seq.length() + 16
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
/**
* Constructs a string builder with no characters in it and an
* initial capacity specified by the {@code capacity} argument.
*
* @param capacity the initial capacity.
* @throws NegativeArraySizeException if the {@code capacity}
* argument is less than {@code 0}.
*/
public StringBuilder(int capacity) {
super(capacity);
}
/**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
* {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
*/
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
/**
* Constructs a string builder that contains the same characters
* as the specified {@code CharSequence}. The initial capacity of
* the string builder is {@code 16} plus the length of the
* {@code CharSequence} argument.
*
* @param seq the sequence to copy.
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
3.3 StringBuilder 常用方法
1. 添加 -- 接受的参数有很多类型,int long float double char boolean char[] CharSequence ...
public StringBuilder append(int i)
public StringBuilder insert(int offset, char c)
2. 删除 -- 删除方法就这两种
public StringBuilder delete(int start, int end)
public StringBuilder deleteCharAt(int index)
3. 查找
public int lastIndexOf(String str)
public int lastIndexOf(String str, int fromIndex)
4. 修改
public StringBuilder replace(int start, int end, String str)
. . .
4. AbstractStringBuilder
4.1 AbstractStringBuilder 介绍
由上面的学习可知,StringBuilder,StringBuffer 均是继承于 AbstractStringBuilder,通过浏览源码其方法具体实现均是调用父类的方法完成。从功能实现上,AbstractStringBuilder 是核心。而AbstractStringBuilder里面唯一的抽象方法是toString()方法。
4.2 AbstractStringBuilder的属性和构造函数
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
/**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
}
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
AbstractStringBuilder 与 String 相比,同是字符数组存储字符串,但 String 中声明的字符数组是 final 类型表示不可修改,而 AbstractStringBuilder 中则可以修改,这就是 StringBuilder、StringBuffer 可实现字符串修改功能的原因。
AbstractStringBuilder 与 String 相比,其底层仍是通过字符数组实现字符串的存储。不同的是多了一个 count 参数,以用于记录实际存储的字符个数,而不是字符数组 value 的长度。
4.3 AbstractStringBuilder的扩容原理
AbstractStringBuilder的扩容原理也即是StringBuilder和StringBuffer的扩容原理,因为两者的实现底层的都是通过AbstractStringBuilder实现的。
/**
* Returns a capacity at least as large as the given minimum capacity.
* Returns the current capacity increased by the same amount + 2 if
* that suffices.
* Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
* unless the given minimum capacity is greater than that.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero or
* greater than Integer.MAX_VALUE
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
/*
* @Native public static final int MAX_VALUE = 0x7fffffff; // 2147483647
* private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
* 扩容算法:
* 如果容量不够,就按照newLength = oldLength << 1 + 2, 将新的容量设置为原来容量的 2 倍加 2
* 如果此时容量还不够,就将容量直接扩展为所需的容量,
* 如果所需容量小于零或者所需容量大于MAX_ARRAY_SIZE,
* 如果所需容量大于Integer.MAX_VALUE,此时发生溢出,抛出异常
* 否则如果就将容量大于MAX_ARRAY_SIZE,就扩容到所需容量
* 否则就扩容到MAX_ARRAY_SIZE
*
* 以上算是对源码的解释,其实可以简记为:
* 每次扩容将容量设置为原容量的 2 倍加 2,
* 如果此时容量还不够,就直接扩容到所需容量。
* 因为不可能真的有一个串的长度有21亿那么长,太过于丧心病狂。
*/
字符串追加源码:
字符串删除源码:
由上面的扩容原理和追加,删除源码可以看出,每次的操作都是通过System类里面的arraycopy方法实现的,事实也是如此,大部分的操作都是基于此的。所以如果可以提前预估出最终的数组长度并在创建对象时提前设置数组大小,对程序运行效率的提高是十分有帮助的。这样可以减少了不断扩容、拷贝的内在时间成本
5. 总结
- AbstractStringBuilder 才是功能方法的具体实现。同 java.lang.String 一样,底层是用字符数组在存储字符串,但区别是 String 中字符数组是 final 类型,而 AbstractStringBuilder 中字符数组是可变的。
- StringBuilder 和 StringBuffer 只是对 java.lang.AbstractStringBuilder 的一个继承封装,通过继承可以实现功能的一个拓展。
- StringBuilder仅仅只是功能的继承;
- StirngBuffer在功能继承上做了一个synchronized加锁的操作,从而实现线程安全性。
- String,StringBuilder 与 StringBuffer 均是 final 类,无法再被继承。
- AbstractStringBuilder 是抽象类,无法实例化。