前言

String类表示字符串。Java程序中所有的字符串字面值,比如"abc",都是使用String实现的。String对象是一个常量,它的值在创建之后就不能被修改了。

相关知识

  • String源码分析
  • StringBuilder源码分析
  • StringBuffer源码分析

源码分析

String类包含了大量的方法,比如:检查字符串中单个字符的方法、比较字符串的方法、搜索字符串的方法、提取子字符串的方法、创建所有的字符都转成大写或者小写的字符串的方法等。

定义

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    ...
}

String类被 final 所修饰,因此不能被继承。String类实现了3个接口:

  • Serializable 序列化接口,表示对象可以被序列化。
  • Comparable 可比较接口,提供了一个compareTo()方法,用来比较两个对象的大小。
  • CharSequence 字符序列接口,提供了几个对字符序列进行只读访问的方法,比如:length()、charAt()、subSequence()、toString()方法等。

主要变量

private final char value[];

private int hash;

其中:

  • value 用来存储字符串中的字符。因此,String类的底层实现是把字符存储在一个char类型的数组中。value数组被 final 所修饰,所以String对象创建之后就不能被修改了。
  • hash 用来缓存计算之后的哈希值。这样就不用每次都重新计算哈希值了。

构造方法

public String() {
    this.value = "".value;
}

public String(byte bytes[]) {
    this(bytes, 0, bytes.length);
}

public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

public String(StringBuffer buffer) {
    synchronized(buffer) {
        this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
    }
}

public String(StringBuilder builder) {
    this.value = Arrays.copyOf(builder.getValue(), builder.length());
}

...

String类提供了一系列的构造方法,它可以接受byte[]、char[]、String、StringBuffer、StringBuilder等多种类型的参数。本质上都是将这些参数中的字符赋值到value数组中。

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;
}

compareTo()方法比较两个字符串的大小。从第一个字符开始按照字典序(‘A’小于’B’,大写字母小于小写字母)逐一地比较字符,一旦一个字符不相等,那么立即返回结果。两个字符串相等时返回0,该字符串小于参数字符串时返回一个负整数,该字符串大于参数字符串时返回一个正整数。

length()方法

public int length() {
    return value.length;
}

length()方法返回该字符串的长度。

charAt()方法

public char charAt(int index) {
    if ((index < 0) || (index >= value.length)) {
        throw new StringIndexOutOfBoundsException(index);
    }
    return value[index];
}

charAt()方法返回该字符串在指定索引处的char字符。索引的范围从0到length() - 1。

subSequence()方法

public CharSequence subSequence(int beginIndex, int endIndex) {
    return this.substring(beginIndex, endIndex);
}

subSequence()方法返回该字符序列的一个子序列。

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);
}

substring()方法返回该字符串中的一个子字符串。如果子字符串刚好是该字符串,那么直接返回该字符串。反之,返回一个新创建的字符串。

equals()方法

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;
}

equals()方法比较该字符串是否与指定的对象相等。如果指定的对象与该字符串是同一个对象,那么直接返回true。反之,只有当指定的对象不为空且是一个与该字符串相同字符序列的字符串对象时才返回true。

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;
}

hashCode()方法返回该字符串的哈希值。只有当缓存的hash值为0(表示未计算过哈希值)并且字符串的长度大于0时才计算哈希值。哈希值的计算公式如下所示:

value[0] * 31^(n-1) + value[1] * 31^(n-2) + ... + value[n-1]

trim()方法

public String trim() {
    int len = value.length;
    int st = 0;
    char[] val = value;    /* avoid getfield opcode */

    while ((st < len) && (val[st] <= ' ')) {
        st++;
    }
    while ((st < len) && (val[len - 1] <= ' ')) {
        len--;
    }
    return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}

trim()方法返回一个删除了起始和结尾空格的子字符串。

总结

  • String类使用了一个final char数组来存储字符。
  • String对象是不可变的。