String类
域
private final char value[];
private int hash; // Default to 0
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
主要注意value和hash这两个域,String内部也是使用数组进行存储数据的,hash是这个字符串对应的哈希码,因为String是不可变的,当String的内容发生变化之后,虚拟机会生成一个新的字符串,并将String的引用只想这个字符串,这样如果String经常发生变化时,字符串常量表里面会有大量的字符串,会浪费内存,为了节约内存空间,一个方法是使用StringBuilder,StringBuilder是可变的,另一个方法就是为每一个不可变的字符串生成一个哈希码,这样如果字符串常量表中有现成的字符串时,就不需要再生成了,直接引用就行了。
为了验证常量字符串的缓存,举个例子:
public class TestDemo1 implements Cloneable {
public static void main(String[] args) throws Exception {
String a = "abc";
String b = "abc";
System.out.println(aString == bString);
}
}
上面程序的最终结果为true.这也证明了a和b指向的是同一个对象,即常量池只有一个"abc"字符串。当然,上面成立的前提是直接将字符串常量赋值给String引用才有效,如果使用new的话,就会在堆中生成对象,即使使用一样的字符串初始化,引用也不会相等。
构造函数
public String() {
this.value = new char[0];
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
不带参数的构造函数,实际上就是空,等价于
public String() {
this.value = "".value;
}
equals方法
String类对Object中equals方法进行了重写,判断的是两个String对象包含的字符串是否相等。
public boolean equals(Object anObject) {
if (this == anObject) { //如果是同一个引用,则直接返回true
return true;
}
if (anObject instanceof String) { //如果anObject 为null,则instanceof返回false
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;
}
compareTo方法
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
String类实现了Comparable接口,所以说String是可比较的,compareTo的返回值是这样的,从两者的第一个字母比较过去,如果有一个字母不相等,则返回大的字母减去小的字母的int值,如果比较完了,则返回两者String的长度之差。符合compareTo方法的返回值要求,即:如果a小于b返回负数,如果a大于b,返回正数,否则返回0.
hashCode方法
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对象的哈希码,并且把哈希码缓存在hash这个域中,避免每次调用都要重新计算。
substring方法
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
返回当前String对象的子序列。
intern方法
public native String intern();
intern方法是一个本地方法,调用该方法,会判断是否常量池中有一个与该String对象相等的对象(也就是equals返回0),如果有返回常量池中的对象,否则,将该String对象添加到常量池中再返回常量池中的对象。
例如:
public class TestDemo1 implements Cloneable {
public static void main(String[] args) throws Exception {
String cString = "abc";
String bString = new String("abc");
String aString = bString.intern();
System.out.println(cString == aString); //返回的是true
}
}