String类内部是一个不可变的字符序列,以jdk7为例,String类源代码如下:
public final class String {
/** The value is used for character storage. */
private final char value[];
public String() {
this.value = new char[0];
}
public String(String original) {
this.value = original.value;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
public int length() {
return value.length;
}
public boolean isEmpty() {
return value.length == 0;
}
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
}
通过jdk源代码可以发现String类的内部是通过char[] value即字符数组实现的。String类本身是final类型的,不可以被其他类继承;内部的字符数组也是final类型的,只能赋值一次。
String类提供了查找功能相关方法:endsWith, startsWith, indexOf,lastIndexOf。
提供比较功能的方法:equals, equalsIgnoreCase, compareTo。
将基本类型数据转为字符串类型:public static String valueOf(…)。
可以调用String类的方法创建并返回一个新的字符串:concat, replace, substring, toLowerCase, toUpperCase, trim。
在使用过程中尽量避免在for里面进行"+"操作
String gh = new String("a");
for(int i=0;i<1000;i++){
gh += i;
}
System.out.printf(gh);
这种拼接字符串的代码很浪费空间,每个线程都会在for里面产生n个对象;另外new String("a")会在堆空间里面产生2个对象,分别是堆空间new出来的String对象,还有常量池里面的"a"对象。
StringBuilder特点:线程不安全、效率高。
StringBuffer特点:线程安全、效率低。由于一般情况下我们使用的是局部变量,所以推荐使用效率高的StringBuilder。
两者都是抽象类AbstractStringBuilder的子类,AbstractStringBuilder内部是char[] value实现的,该字符数组并没有使用private final进行修饰(即可变)。源代码如下:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* 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];
}
所以两者都是可变字符序列。查看StringBuffer的源代码,
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
/** use serialVersionUID from JDK 1.0.2 for interoperability */
static final long serialVersionUID = 3388685877147921107L;
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
通过其构造函数可见StringBuffer默认是16位长度的字符数组。如果需要存放特别长(超过16位)的子字符串时怎么办的呢,具体的扩容机制在AbstractStringBuilder类,源代码是:
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;
}
之所以认为StringBuffer是线程安全的,是因为它里面的方法都是同步方法,源代码如下:
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
这两个类中每调用一次处理字符串的方法都会返回一次this属性,即返回char数组本身,说明了这两个类都是可变字符序列,这两个类中的方法是支持链式调用的,源代码见append方法返回值: