一、String定义
String是一个用 final 声明的常量类,不能被任何类所继承,而且一旦一个String对象被创建,包含在这个对象中的字符序列是不可改变的, 包括该类后续的所有方法都是不能修改该对象的。 实现了Serializable接口,这是一个序列化标志接口,还实现了Comparable接口,用于比较两个字符串的大小(按顺序比较单个字符的ASCII码),后面会有具体方法实现;最后实现了CharSequence接口,表示是一个有序字符的集合。
常量池:Java运行时会维护一个String Pool(String池), 也叫“字符串缓冲区”。String池用来存放运行时中产生的各种字符串,并且池中的字符串的内容不重复。
二、String源代码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** 用于字符存储. */
private final char value[];
/** 存放hash code */
private int hash; // Default to 0
//在 java的很多类中都会重写equals和hashCode方法,这是为什么呢?最常见的String类,比如我定义两个字符相同的字符串,那么对它们进 行比较时,我想要的结果应该是相等的,如果你不重写equals和hashCode方法,他们肯定是不会相等的,因为两个对象的内存地址不一样。
//先比较对象,如果不相等返回false,否则判断比较对象是否是String类型,如果不是返回false,否则比较它们的字符串长度,如果不一致则返回false,否则将它们的值一一比较,如果不一致返回false,否则返回true。
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;
}
//该算法实现数学表达式:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
}
三、常量与变量的显著区别
String类是依赖一个私有字符常量数组实现的
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
StringBuffer与StringBuilder都是继承AbstractStringBuilder,然而AbstractStringBuilder类是依赖一个字符变量数组实现的
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
四、线程安全分析
所有对String发生修改的方法返回值都是一个新的String对象,没有修改原有对象
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}
StringBuffer所有写操作都被synchronized修饰了,所以所有修改操作都是串行的
@Override
public synchronized StringBuffer replace(int start, int end, String str) {
toStringCache = null;
super.replace(start, end, str);
return this;
}
而StringBuilder的写操作则没有使用synchronized进行修饰,也不包含其他串行化修改的算法,多线程情况下会出错
@Override
public StringBuilder replace(int start, int end, String str) {
super.replace(start, end, str);
return this;
}
五、性能、速度分析
StringBuilder > StringBuffer > String
(1) 在编译阶段就能够确定的字符串常量,完全没有必要创建String或StringBuffer对象。直接使用字符串常量的"+"连接操作效率最高。如:
str = "a" + "b";
(2) 此外StringBuffer对象的append效率要高于String对象的"+"连接操作。如:
String s1="Heart";
String s="";
for(int i=0;i<10000;i++){
s=s+s1;
}
(3)StringBuffer使用了synchronized,效率相对低一些。